Das Format () der Golf-Saite ist umgekehrt

13

Invertieren Sie die Format-Methode.

Die FormatMethode der String-Klasse (oder gleichwertig wie sprintf) ist in den meisten Sprachen verfügbar. Grundsätzlich ist ein "Format" -String erforderlich, der Platzhalter mit einer zusätzlichen Formatierung sowie null oder mehr Werte enthalten kann, die anstelle dieser Platzhalter eingefügt werden sollen.

Ihre Aufgabe ist es, die Umkehrfunktion in der Sprache Ihrer Wahl zu implementieren.

API

Der Methodenname sollte entweder format1oder sein deformat.

Eingabe : Der erste Parameter ist die Zeichenfolge "Format", genau wie bei der ursprünglichen Formatierungsmethode. Der zweite Parameter ist der analysierte String (siehe Beispiele unten). Es sind keine weiteren Parameter erforderlich oder zulässig.

Ausgabe : Ein Array (oder das Äquivalent der Sprache Ihrer Wahl) von Werten, die entsprechend den Platzhaltern im Format extrahiert wurden.

Die Platzhalter sind {0}, {1}, {2}etc.

Im Falle eines schlechten Formats können Sie einen Fehler auslösen oder das zurückgeben, was Sie möchten.

Im Falle einer ungültigen Eingabe können Sie einen Fehler auslösen oder das zurückgeben, was Sie möchten. Ungültige Eingabe ist eine solche , die nicht von String.Format mit demselben Format - String, zum Beispiel erzeugt werden können: '{0}{0}', 'AAB'.

Beispiele

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

Mehrdeutigkeit

Im Zweifelsfall können Sie jede geeignete Antwort zurückgeben. Beispielsweise:

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

Noch ein paar Regeln

  • Zur Vereinfachung muss die Formatierung nicht unterstützt werden. Sie können alles über führende Nullen, Dezimalstellen oder Rundungsprobleme vergessen. Generieren Sie einfach die Werte als Zeichenfolgen.
  • Um es nicht trivial zu machen, sind reguläre Ausdrücke nicht erlaubt .
  • Sie müssen sich bei der Eingabe nicht um geschweifte Klammern kümmern (dh der zweite Eingabeparameter enthält keine {s oder }s).

Gewinnen

Das ist ! (sollte als "Dies ist Sparta!" gelesen werden) Die richtige Funktion mit der kürzesten Länge gewinnt. Standardlücken sind verboten.

Jakob
quelle
In dem Beispiel deformat('{0}{1}{0}', 'ABBA') => ['A', 'BB'], was passiert , wenn wir statt gegeben deformat('{0}{1}{0}', 'AAAA')?
Xnor
@xnor - als wir eine Mehrdeutigkeit haben, und jede der folgenden wäre eine gültige Ausgabe: ['', 'AAAA'], ['A', 'AA'],['AA', '']
Jacob
Könnte man dann ausgegeben haben deformat('{0}{1}{0}', 'ABBA') => ['', 'ABBA']? Wenn ja, gibt es eine billige Lösung, es sei denn, jede Zeichenfolge erscheint mindestens zweimal.
Donnerstag,
Funktioniert Ihre billige Lösung auch für deformat('{0}_{1}_{0}', 'A_BB_A')?
Jacob
Oh, ich verstehe, ich hatte die tatsächlichen Charaktere in den Ergebnissen vergessen. Ich versuche immer noch, mich darum zu kümmern, wie algorithmisch schwierig das ist. Lassen Sie mich sehen, ob ich eine wirklich perverse Instanz erfinden kann.
Donnerstag,

Antworten:

2

Haskell, 220 Zeichen

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

Bricht ab, wenn Sie mehrere Darstellungen für dasselbe Muster ( {1}vs {01}) verwenden - erzwingt nicht deren Gleichheit und verwirft stattdessen Übereinstimmungen für alle außer einer Darstellung.

19 Zeichen können durch Weglassen gespeichert werden, mapKeys((0+).read)$wenn die richtige Reihenfolge von Übereinstimmungen mit mehr als 10 Mustern keine Rolle spielt oder wenn möglicherweise ein Auffüllen mit derselben Länge erforderlich ist oder wenn die Reihenfolge der Zeichenfolgen für Muster akzeptabel ist. In jedem Fall wird ein Muster, wenn es im ersten Argument weggelassen wird, auch im Ergebnis weggelassen.

Wenn Sie !!0vom Ende entfernen, wird format1die Liste aller Lösungen und nicht nur die erste zurückgegeben.

vor dem Golfen:

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
quelle
was ist da (0+)? wird das schreiben nicht einfach kürzer gelesen?
stolzer Haskeller
@proudhaskeller readlässt Sie nur mit einem mehrdeutigen Typ. Haskell weiß nicht, unter welchem ​​bestellbaren Typ die Schlüssel gelesen werden sollen. +0erzwingt eine Zahl, aus der Haskell bereits eine willkürliche Wahl treffen kann und geht für ganze Zahlen.
John Dvorak
2

Ruby, 312 Zeichen

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

Sie könnten 5 Zeichen speichern, indem Sie Übereinstimmungen mit der Länge Null bevorzugen und die ABBALösung erstellen ['', 'ABBA'], anstatt die bevorzugte Lösung der Frage. Ich habe mich dafür entschieden, die Beispiele als impliziten Teil der Spezifikation zu interpretieren.

Nathan Baum
quelle
1

Python, 208 Zeichen, wenn auch unvollständig.

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

Die Funktion durchsucht beide Zeichenfolgen gleichzeitig, bis sie eine öffnende Klammer in der Eingabezeichenfolge findet, die einen Platzhalter kennzeichnet.

In diesem Fall wird davon ausgegangen, dass der Platzhalter bereits erweitert wurde, und versucht, den Index der Ausgabezeichenfolge anhand der Liste der bisher gefundenen Werte nach oben zu verschieben.

Wenn es nicht erweitert wurde, fügt es der Werteliste einen neuen Eintrag hinzu und beginnt mit dem Hinzufügen von Zeichen aus der Ausgabezeichenfolge, bis es das Zeichen nach dem Platzhalter in der Eingabezeichenfolge erreicht.

Wenn das Ende der Eingabezeichenfolge erreicht ist, werden die bisher gefundenen Werte zurückgegeben.


Es funktioniert gut für einfache Eingaben, hat aber eine Reihe von Problemen:

  • Es erfordert ein bekanntes Trennzeichen nach jedem Platzhalter in der Eingabe, daher funktioniert es nicht mit Platzhaltern, die direkt nebeneinander stehen, z. B. "{0} {1}". Aus diesem Grund musste ich an beide Zeichenfolgen ein Leerzeichen anhängen.

  • Es wird davon ausgegangen, dass die ersten Instanzen jedes Platzhalters in der richtigen Reihenfolge sind, z. B. "{ 0 } { 1 } {1} {0} { 2 }".

  • Es funktioniert nur für die ersten 10 Platzhalter, da davon ausgegangen wird, dass sie alle 3 Zeichen lang sind.

  • Es behandelt überhaupt keine mehrdeutigen Fälle :(

Sam Hubbard
quelle
1

C ++ 11-Code, 386 Zeichen

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

Die Funktion format1 hat 2 Zeichenfolgen als Eingabe (const char *) und gibt eine Hashmap mit den Schlüsseln integer (das Muster) zurück und value ist die identifizierte Zeichenfolge. Wenn nichts gefunden wird oder ein Fehler vorliegt, wird eine leere Hashmap zurückgegeben.

Verwendung:

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

Ausgabe:

1=one
2=two

Beispiel 2:

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

Ausgabe:

one and two

Die Muster sind dezimal dargestellt, die Eingaben sind größer als MAXINTder Überlauf, aber es funktioniert immer noch.

Obwohl es kleinere Lösungen in anderen Programmiersprachen gibt, ist dies das kleinste C ++ - noch! :)

Dies ist der Code vor dem Golfen:

#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
quelle