Formato del golf string () inverso


13

Invertire il metodo di formattazione.

Il Formatmetodo della classe String (o equivalente, come sprintf) è disponibile nella maggior parte delle lingue. Prende sostanzialmente una stringa "Format" che può contenere segnaposto con una formattazione aggiuntiva e zero o più valori da inserire al posto di quei segnaposto.

Il tuo compito è implementare la funzione inversa nella tua lingua preferita.

API

Il nome del metodo dovrebbe essere format1o deformat.

Input : il primo parametro sarà la stringa "Formato", proprio come nel metodo di formato originale. Il secondo parametro sarà la stringa analizzata (vedere gli esempi seguenti). Non sono necessari né consentiti altri parametri.

Output : un array (o l'equivalente della lingua scelta) di valori estratti in modo corrispondente con i segnaposto nel formato.

I segnaposto sono {0}, {1}, {2}, etc.

In caso di formato errato, potresti generare un errore o restituire quello che preferisci.

In caso di input non valido, è possibile generare un errore o restituire ciò che si desidera. Ingresso valido è tale che non può essere generato da String.Format utilizzando stessa stringa di formato, ad esempio: '{0}{0}', 'AAB'.

Esempi

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']

Ambiguità

In caso di ambiguità è possibile restituire qualsiasi risposta adeguata. Per esempio:

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

Alcune altre regole

  • Per semplificare, non è necessario supportare effettivamente la formattazione. Puoi dimenticare tutto sui principali zeri, virgola decimale o problemi di arrotondamento. Basta generare i valori come stringhe.
  • Per renderlo non banale, le espressioni regolari non sono consentite .
  • Non è necessario prendersi cura di parentesi graffe in ingresso (cioè il parametro 2 ° ingresso non conterrà alcun {s o }s).

vincente

Questo è ! (va letto come "This is Sparta!") vince la funzione corretta che ha la lunghezza più breve. Sono vietate le scappatoie standard .


Nell'esempio deformat('{0}{1}{0}', 'ABBA') => ['A', 'BB'], cosa succede se invece ci venisse dato deformat('{0}{1}{0}', 'AAAA')?
xnor

@xnor - quello che abbiamo un'ambiguità, e ciascuno dei seguenti sarebbe un'uscita valida: ['', 'AAAA'], ['A', 'AA'],['AA', '']
Jacob

Si sarebbe potuto quindi emettere uno deformat('{0}{1}{0}', 'ABBA') => ['', 'ABBA']? In tal caso, esiste una soluzione economica a meno che ogni stringa non appaia almeno due volte.
xnor

funzionerà anche la tua soluzione economica deformat('{0}_{1}_{0}', 'A_BB_A')?
Jacob,

Oh, vedo, mi ero dimenticato dei personaggi reali nei risultati. Sto ancora cercando di capire quanto sia algoritmicamente difficile. Fammi vedere se riesco a inventare un'istanza davvero perversa.
xnor

Risposte:


2

Haskell, 220 caratteri

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

Si interrompe se si utilizzano più rappresentazioni per lo stesso modello ( {1}vs {01}) - non impone la loro uguaglianza, scartando invece le corrispondenze per tutte tranne una.

19 caratteri possono essere salvati omettendo mapKeys((0+).read)$se l'ordine corretto di corrispondenze superiori a 10 motivi non ha importanza, o se può essere richiesta un'imbottitura della stessa lunghezza o se è accettabile l'ordine delle stringhe di motivi. In ogni caso, se uno schema viene omesso dal primo argomento, viene omesso anche dal risultato.

La rimozione !!0dalla fine consente di format1restituire l'elenco di tutte le soluzioni, anziché solo la prima.

prima di giocare a 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

chi c'è (0+)? la scrittura non è più breve?
orgoglioso haskeller l'

@proudhaskeller readti lascia solo con un tipo ambiguo. Haskell non sa quale tipo ordinabile leggere le chiavi. +0forza un numero, dal quale Haskell è già in grado di fare una scelta arbitraria e va per numeri interi.
John Dvorak,

2

Rubino, 312 caratteri

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 caratteri possono essere salvati preferendo corrispondenze di lunghezza zero, creando la ABBAsoluzione ['', 'ABBA'], piuttosto che la soluzione preferita della domanda. Ho scelto di interpretare gli esempi come parte implicita della specifica.


1

Python, 208 caratteri, anche se incompleto.

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

La funzione sposta simultaneamente entrambe le stringhe, fino a quando non trova una parentesi graffa di apertura nella stringa di input, indicando un segnaposto.

Quindi, presuppone che il segnaposto sia già stato espanso e tenta di far avanzare l'indice della stringa di output passandolo attraverso l'elenco dei valori trovati finora.

Se non è stato espanso, aggiunge una nuova voce all'elenco di valori e inizia ad aggiungere caratteri dalla stringa di output fino a quando non raggiunge il carattere dopo il segnaposto nella stringa di input.

Quando arriva alla fine della stringa di input, restituisce i valori trovati finora.


Funziona bene con input semplici, ma ha una serie di problemi:

  • Richiede un delimitatore noto dopo ciascun segnaposto nell'input, quindi non funziona con i segnaposto uno accanto all'altro, ad esempio "{0} {1}". Questo è il motivo per cui avevo bisogno di aggiungere un carattere spaziale ad entrambe le stringhe.

  • Presuppone che le prime istanze di ciascun segnaposto siano in ordine, ad esempio "{ 0 } { 1 } {1} {0} { 2 }".

  • Funziona solo per i primi 10 segnaposto poiché presuppone che siano tutti e 3 i caratteri.

  • Non gestisce affatto casi ambigui :(


1

Codice C ++ 11, 386 caratteri

#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;}

La funzione format1 ha 2 stringhe come input (const char *) e restituisce un hashmap con chiavi integer (il modello) e value è la stringa identificata. Se non viene trovato nulla o si verifica un errore, viene restituita una hashmap vuota.

Uso:

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

Produzione:

1=one
2=two

Esempio 2:

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

Produzione:

one and two

Gli schemi sono in rappresentazione decimale, gli input più grandi di quelli MAXINTche traboccano ma funzionano ancora.

Anche se ci sono soluzioni più piccole in altri linguaggi di programmazione, questo è il C ++ più piccolo di sempre! :)

Questo è il codice prima del 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;
}
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.