Format () terbalik Golf String

13

Balikkan metode Format.

The Formatmetode kelas String (atau equivallent, sepertisprintf ) tersedia dalam banyak bahasa. Pada dasarnya dibutuhkan string "Format" yang mungkin berisi placeholder dengan beberapa format tambahan, dan nol atau lebih nilai yang akan dimasukkan daripada placeholder itu.

Tugas Anda adalah mengimplementasikan fungsi terbalik dalam bahasa pilihan Anda.

API

Nama metode harus berupa format1ataudeformat .

Memasukkan : Parameter 1 akan menjadi string "Format", seperti dalam metode format asli. Parameter ke-2 adalah string yang diurai (lihat contoh di bawah). Tidak ada parameter lain yang diperlukan atau diizinkan.

Keluaran : array (atau bahasa pilihan Anda) dari nilai-nilai yang diekstraksi sesuai dengan placeholder dalam format.

Penampung yang {0}, {1}, {2}, dll

Dalam hal format yang buruk Anda dapat melakukan kesalahan, atau mengembalikan apa pun yang Anda suka.

Dalam hal input tidak valid, Anda dapat melakukan kesalahan, atau mengembalikan apa pun yang Anda suka. Masukan tidak valid adalah sedemikian rupa sehingga tidak dapat dihasilkan oleh String.Format menggunakan format string yang sama, misalnya: '{0}{0}', 'AAB'.

Contohnya

deformat('{0} {1}', 'hello world') => ['hello', 'world']
deformat('http{0}://', 'https://') => ['s']
deformat('http{0}://', 'http://') => [''] // array of one item which is an empty string
deformat('{0}{1}{0}', 'ABBA') => ['A', 'BB']

Kemenduaan

Dalam hal ambiguitas Anda dapat mengembalikan jawaban yang sesuai. Sebagai contoh:

deformat('{0} {1}', 'Edsger W. Dijkstra')
// both ['Edsger', 'W. Dijkstra'] and ['Edsger W.', 'Dijkstra'] are applicable.

Beberapa Aturan Lagi

  • Untuk membuatnya lebih mudah, tidak perlu benar-benar mendukung pemformatan. Anda bisa melupakan semua tentang angka nol di depan, titik desimal atau masalah pembulatan. Hanya menghasilkan nilai sebagai string.
  • Untuk membuatnya non-sepele, Ekspresi Reguler tidak diperbolehkan .
  • Anda tidak perlu menjaga kurung kurawal dalam input (mis. Parameter input kedua tidak akan mengandung {s atau }s).

Kemenangan

Ini ! (harus dibaca sebagai "Ini Sparta!") fungsi yang benar memiliki kemenangan terpendek. Celah standar dilarang.

Yakub
sumber
Dalam contoh deformat('{0}{1}{0}', 'ABBA') => ['A', 'BB'], bagaimana jika kita malah diberikan deformat('{0}{1}{0}', 'AAAA')?
xnor
@xnor - dari kita memiliki ambiguitas, dan masing-masing berikut ini akan menjadi keluaran yang valid: ['', 'AAAA'], ['A', 'AA'],['AA', '']
Jacob
Bisakah seseorang mengeluarkannya deformat('{0}{1}{0}', 'ABBA') => ['', 'ABBA']? Jika demikian, ada solusi murah kecuali setiap string muncul setidaknya dua kali.
xnor
apakah solusi murah Anda juga akan berhasil deformat('{0}_{1}_{0}', 'A_BB_A')?
Jacob
Oh, begitu, saya sudah lupa tentang karakter yang sebenarnya dalam hasil. Saya masih mencoba untuk membungkus kepala saya di sekitar betapa sulitnya algoritma ini. Biarkan saya melihat apakah saya bisa menjadi contoh yang sangat buruk.
xnor

Jawaban:

2

Haskell, 220 karakter

import Data.Map;f""""=[empty]
f('{':b)d=[insert k m b|(k,('}':a))<-lex b,(m,c)<-[splitAt n d|n<-[0..length d]],b<-f a c,notMember k b||b!k==m]
f(x:b)(y:d)|x==y=f b d;f _ _=[];format1 x y=elems$mapKeys((0+).read)$f x y!!0

Istirahat jika Anda menggunakan beberapa representasi untuk pola yang sama ( {1}vs {01}) - tidak menegakkan kesetaraan mereka, membuang kecocokan untuk semua kecuali satu representasi.

19 karakter dapat disimpan dengan menghilangkan mapKeys((0+).read)$jika urutan yang cocok dari 10 pola tidak masalah, atau jika padding dengan panjang yang sama mungkin diperlukan, atau jika urutan pola dapat diterima. Bagaimanapun, jika suatu pola dihilangkan dari argumen pertama, itu juga dihilangkan dari hasilnya.

Menghapus !!0dari ujung akan format1mengembalikan daftar semua solusi, bukan hanya yang pertama.

sebelum bermain golf:

import Data.Map
import Control.Monad

cuts :: [a] -> [([a],[a])]
cuts a=[splitAt n a | n <- [0..length a]]

f :: String -> String -> [Map String String]
-- empty format + empty parsed = one interpretation with no binding
f "" "" = [empty]
-- template-start format + some matched = branch search
f ('{':xs) ys = do
    let [(key, '}':xr)] = lex xs
    (match, yr) <- cuts ys
    b <- f xr yr
    guard $ notMember key b || b!key == match
    return $ insert key match b
-- non-empty format + matching parsed = exact match
f (x:xs) (y:ys) | x == y = f xs ys
-- anything else = no interpretation
f _ _ = []

deformat :: String -> String -> [String]
deformat x y = elems $ mapKeys ((0+).read) $ head $ f x y
John Dvorak
sumber
mengapa ada (0+)? bukan hanya tulisan yang dibaca lebih pendek?
haskeller bangga
@proudhaskeller hanya readmenyisakan Anda dengan tipe yang ambigu. Haskell tidak tahu tipe apa yang bisa dipesan untuk membaca kunci. +0memaksa nomor, dari mana Haskell sudah dapat membuat pilihan sewenang-wenang dan berlaku untuk bilangan bulat.
John Dvorak
2

Ruby, 312 karakter

class String
def-@
self[0,1].tap{self[0,1]=''}end
end
def format1 f,s,r=[]
loop{if'{'==c=-f
n,f=f.split('}',2)
[*1..s.length,0].each{|i|next if'{'!=f[0]&&s[i]!=f[0]
if u=format1((g=f.gsub("{#{n}}",q=s[0,i])).dup,s[i..-1],r.dup)
r,s,f=u,s[i..-1],g
r[n.to_i]=q
break
end}else
c!=-s&&return
end
""==c&&break}
r
end

5 karakter dapat diselamatkan dengan memilih kecocokan dengan panjang nol, membuat ABBAsolusi ['', 'ABBA'], dan bukan solusi yang disukai pertanyaan. Saya memilih untuk menafsirkan contoh sebagai bagian tersirat dari spesifikasi.

Nathan Baum
sumber
1

Python, 208 karakter, meskipun tidak lengkap.

def format1(i,o):
 i+=" ";o+=" ";x=y=0;s=[]
 while x<len(i):
  if i[x]=="{":
   try:y+=len(s[int(i[x+1])])
   except:
    s+=[""]
    while o[y]!=i[x+3]:s[int(i[x+1])]+=o[y];y+=1
   x+=3
  x+=1;y+=1
 return s

Fungsi menyapu kedua string secara bersamaan, sampai menemukan penjepit pembuka di string input, menandakan placeholder.

Kemudian, diasumsikan placeholder telah diperluas, dan mencoba untuk memajukan indeks string keluaran melewatinya dengan melihat daftar nilai yang ditemukan sejauh ini.

Jika belum diperluas, ia akan menambah entri baru ke daftar nilai, dan mulai menambahkan karakter dari string output hingga mencapai karakter setelah placeholder di string input.

Ketika sampai di akhir string input, ia mengembalikan nilai yang ditemukan sejauh ini.


Ini berfungsi dengan baik untuk input sederhana, tetapi memiliki sejumlah masalah:

  • Ini membutuhkan pembatas yang diketahui setelah setiap placeholder dalam input, sehingga tidak bekerja dengan placeholder tepat di sebelah satu sama lain yaitu "{0} {1}". Inilah sebabnya saya perlu menambahkan char space ke kedua string.

  • Itu mengasumsikan contoh pertama dari setiap placeholder berada dalam urutan misalnya "{ 0 } { 1 } {1} {0} { 2 }".

  • Ini hanya berfungsi untuk 10 penampung pertama karena mengasumsikan panjangnya 3 karakter.

  • Sama sekali tidak menangani kasus ambigu :(

Sam Hubbard
sumber
1

Kode C ++ 11, 386 karakter

#include <string>
#include <map>
using namespace std;using _=map<int,string>;using X=const char;_ format1(X*p,X*s,_ k=_()){_ r;while(*p!='{'){if(!*p||!*s){return*p==*s?k:r;}if(*p++!=*s++)return r;}int v=0;while(*++p!='}'){v=v*10+(*p-48);}p++;if(k.find(v)!=k.end()){return format1((k[v]+p).c_str(),s,k);}while((r=format1(p,s,k)).empty()){k[v]+=*s++;if(!*s){return*p==*s?k:r;}}return r;}

Fungsi format1 memiliki 2 string sebagai input (const char *) dan mengembalikan hashmap dengan integer kunci (pola) dan nilai adalah string yang diidentifikasi. Jika tidak ada yang ditemukan atau kesalahan, hashmap kosong dikembalikan.

Pemakaian:

for (auto v : format1("{1} {2}", "one two")){
    cout << v.first << "=" << v.second << endl;
}

Keluaran:

1=one
2=two

Contoh 2:

auto v = format1("{1} {2}", "one two");
cout << v[1] << " and " << v[2] << endl;

Keluaran:

one and two

Pola dalam representasi desimal, input lebih besar dari yang MAXINTakan meluap tetapi masih berfungsi.

Meskipun ada solusi yang lebih kecil dalam bahasa pemrograman lain, ini adalah C ++ terkecil - namun! :)

Ini adalah kode sebelum bermain golf:

#include <string>
#include <map>
using namespace std;

using res = map<int,string>;

res format1(const char* p, const char* s, res k=res()){
    res r; // intermediate result, empty until the end
    // match until first '{'
    while (*p != '{'){
        if (!*p || !*s){
            // exit case
            return ((*p == *s) ? k : r); // == 0
        }
        if (*p++ != *s++)
               return r;
    }

    // *p == '{'
    int v = 0;
    while(*++p != '}'){
        v = v*10 + (*p - '0');
    }
    p++; // advance past '}'

    // match back-references
    if (k.find(v) != k.end()){
       return format1((k[v]+p).c_str(), s, k);
    }

    // recursive search
    while ( (r=format1(p, s, k)).empty() ){
        k[v] += *s++;
        if (!*s){
            return *p == *s ? k : r;
        }
    }
    return r;
}
Ovidiu Andoniu
sumber