Warum wird "23 Dogs" am 23. November 2015 geparst, aber "3 Dogs" gibt einen Parserfehler?

8

Ich habe das folgende Code-Snippet auf Twitter gefunden (siehe Post-Verlauf für die Quelle).

%Vor%

Ist das nur ein Osterei in hebeln? Wenn ja, warum dieses bestimmte Datum und Ergebnis? Wenn es kein Osterei ist, warum analysiert 23 Dogs zu einem Datum, aber 3 Dogs analysiert nicht?

    
Nzall 23.11.2015, 20:15
quelle

2 Antworten

7

Das hat nichts mit Pry zu tun. Wenn Sie das Dokument für Datum :: analysieren Sie werden sehen, "Wenn das optionale zweite Argument [ comp ] wahr [der Standardwert] ist und das erkannte Jahr im Bereich" 00 "bis" 99 "liegt, wird das Jahr als zweistelliges Formular betrachtet und gemacht es ist voll. ".

Das ist zugegebenermaßen seltsam. Er erkennt "23" im Bereich "00".."30" (aber nicht "3" oder irgendeiner von "0".."9" ) und schließt damit, dass es ein Datum ist. Beachten Sie, dass jeder Wert im Bereich "31".."99" ebenfalls eine Ausnahme auslöst. Ich erwarte, dass das "30" das obere Ende der Bandbreite ist, da es derzeit November und November 30 Tage sind. Es scheint dann diese Informationen zu verwerfen und das aktuelle Jahr und den aktuellen Monat zu verwenden, und wir nehmen an, dass der Tag "23" ist (oder eine Ausnahme auslösen, wenn beispielsweise "31" eingegeben wurde). Kann mir jemand die Details erklären?

    
Cary Swoveland 23.11.2015, 20:57
quelle
2

Es hat also nichts mit Haschisch zu tun. Ich kann Ihren Bericht in Ruby 2.2.2 in Ruby-Code reproduzieren, der überhaupt keinen Hasch auslöst.

Also warum zum Teufel ist Date.parse bereit, "23 Hunde" zu parsen und sich etwas einfallen zu lassen? Ich habe keine Ahnung. Ich würde sagen, es ist eine Eigenheit oder sogar ein Fehler in Date's Parsing; es versucht, alle möglichen Dinge zu analysieren, aber dies führt zu einigen seltsamen Randfällen.

Verwenden Sie Datum # strptime statt. Verwenden Sie das chronische Juwel, um ein natürlicheres Parsing von Daten in natürlicher Sprache in unvorhersehbaren Formaten zu ermöglichen.

Persönlich verwende ich niemals gradual Date.parse , weil es irgendwie unberechenbar ist, stattdessen eine dieser beiden Methoden zu verwenden. (Oder bestimmte Format-Parsing-Methoden wie Date.iso8601 ).

Ich habe versucht, den MRI-Code für Date.parse zu betrachten, weil ich neugierig war, ob ich herausfinden könnte, was es macht. Aber schnell ging ich in C-Code verloren Ich war nicht kompetent zu verstehen oder zu folgen, und musste aufgeben.

Interessanterweise reproduziert dies auch in JRuby 1.7.10 (ich habe jruby 9x noch nicht installiert). "23 Hunde" parsieren zur selben Sache, "3 Hunde" wirft auf. Hm, vielleicht ist der JRuby-Java-Code für einige von uns verständlicher als der C-Code von MRI. Aber ich hatte noch keine Zeit zu versuchen, durchzuarbeiten, was Date # in JRuby tut. Das Fleisch davon vielleicht beginnt hier , obwohl ich den richtigen Ort für die aktuelle Version nicht gefunden habe. Sie können sehen, dass es versucht, das Datum nach einer Reihe von verschiedenen Formaten in der Folge zu analysieren, wobei es anhält, wenn es nach einem bestimmten Format erfolgreich analysiert wird. Wir können erraten, dass es ein seltsames Format in dieser Liste gibt, das erfolgreich "23 Hunde", aber nicht "3 Hunde" parst. Es ist wahrscheinlich kein Osterei oder absichtlich; Es ist nur ein seltsamer Nebeneffekt, wenn man versucht, ein Datum zu parsen, indem man nur versucht zu erraten, in welchem ​​Format es ist, und verschiedene Formate nacheinander ausprobiert, kein sehr ausgefeilter Algorithmus.

update Okay, zumindest in dem jruby-Code, den ich mir angesehen habe (was vielleicht nicht die aktuelle Implementierung ist, aber eine Implementierung)

  • Nach Versuchen mit anderen möglichen Parsern, die fehlschlagen, versucht es Date._parse_ddd - für beide Eingaben.

  • Date._parse_ddd("23 dogs", e) gibt true zurück und füllt das Date :: Parse :: Bag mit einer mday -Komponente, aber Date._parse_ddd("3 dogs", e) gibt false zurück und füllt nicht Bag . Alles andere folgt von hier.

  • Wenn wir uns die Date._parse_ddd ansehen Implementierung ... gibt es einige Monster Regexes und seltsame Logik. Wahrscheinlich aus der MRT kopiert, um mit der MRT konsistent zu sein, oder anderweitig mit dem MRT-Verhalten konsistent gemacht zu werden.

  • Ich habe keine Lust, weiter zu debuggen. Du kannst wenn du willst. Die JRuby-Implementierung wird, wie Sie sehen können, tatsächlich in Ruby geschrieben, nicht einmal in Java.

Sie oder ich oder jemand könnte versuchen, weiter zu debuggen (vielleicht sogar mit einem interaktiven Debugger auf JRuby-stdlib-Implementierung), genau herauszufinden, was vor sich geht. Aber ich bin zuversichtlich, dass die Antwort nur im Grunde ist "es ist ein seltsamer Nebeneffekt von Date.parse nicht wirklich zu wissen, welches Format es Eingabe ist, aber nur eine Menge Dinge zu versuchen, mit einem nicht sehr ausgefeilten Algorithmus, manchmal seltsame Dinge passieren"

more update : Beachten Sie, dass Date.parse("03 dogs") nicht aufruft, sondern analysiert. Also zwei Zahlen, die es entscheidet, sind analysierbar, eine nicht. Aber natürlich funktioniert Date.parse("3 May") gut. Es ist nicht so, dass Date.parse zweistellige Daten benötigt, es ist nur, dass es eine ganze Reihe von verschiedenen Arten der Analyse versucht, und ein wirklich gutes Datum wird korrekt abgefangen, aber ein falsches Datum könnte von einer der Denkweisen erfasst werden es schien gut genug zu sein, aber in diesem Fall war es falsch.

mehr Gedanken Es ist also nicht beabsichtigt, dass es so parst. Es ist ein Nebenprodukt heuristischer Regeln, die dazu gedacht sind, andere Daten zu erfassen. Da der Code nicht kommentiert ist, können wir nicht genau sagen, welche Datentypen welche Teile fangen sollen. Es ist eine Art Haufen zusammengewürfelter Sachen, um Daten in einer Vielzahl von Formaten, einschließlich internationaler Formate, zu finden.

Sie können sich die Tests ansehen, um alle Arten von Daten zu sehen, die es erfassen soll. Oder Sie könnten versuchen, den Code durchzugehen, um genau zu verstehen, welche Zeilen zu dem Verhalten führen, das Sie sehen. Der Code ist verwirrend - besonders der C-Code in der MRT für die meisten von uns. Der reine Ruby-Code in JRuby ist für uns Rubinisten natürlich besser lesbar. Da es verwirrend und zeitaufwendig ist, den Code zu durchlaufen, mit wenig Nutzen (wen interessiert das?), wirst du wahrscheinlich niemanden dazu bringen, das für dich zu tun.

    
jrochkind 23.11.2015 21:31
quelle

Tags und Links