2015-11-23 23 views
8

Ich habe das folgende Code-Snippet auf Twitter gefunden (siehe Beitragshistorie für die Quelle).Warum wird "23 Dogs" am 23. November 2015 in Pry geparst, aber "3 Dogs" gibt einen Parserfehler?

[5] pry(main)> Date.parse('3 Dogs') 
ArgumentError: invalid date 
[6] pry(main)> Date.parse('23 Dogs') 
=> Mon, 23 Nov 2015 

Ist dies 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 wird nicht analysiert?

+0

* Ist das nur ein Osterei in hebeln? * Ja, nur hacken würde dieses Ergebnis produzieren. Wenn Sie diesen Code in einem Ruby-Programm oder in irb ausführen würden, würde Date.parse() Folgendes erzeugen: "Hello world" für diese Daten. Was bekommen Sie für 'Date.parse ('23')' und 'Date.parse ('3')'? – 7stud

+1

Eigentlich sollte in beiden Fällen 'NameError: nicht initialisiertes konstantes Datum' auftreten. –

+0

@ 7stud Ich weiß nicht, ich habe nicht Pry installiert. Wenn nur pry dieses Ergebnis liefert, ist das so, weil es so hart codiert war, oder weil pry einen anderen Date-Parser hat? Und warum gibt es dieses Ergebnis? – Nzall

Antwort

7

Dies hat nichts mit Pry zu tun. Wenn Sie das Dokument unter Date::parse untersuchen, sehen Sie Folgendes: "Wenn das optionale zweite Argument [comp] wahr [der Standardwert] ist und das erkannte Jahr im Bereich" 00 "bis" 99 "liegt, wird das Jahr als 2-stellig betrachtet Form und macht es voll. ".

Das ist zugegebenermaßen seltsam. Es erkennt "23" im Bereich "00".."30" (aber nicht "3" oder einer der "0".."9"), so 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 Palette ist, weil es derzeit November und November 30 Tage hat. Es scheint dann diese Informationen zu verwerfen und das aktuelle Jahr und den aktuellen Monat zu verwenden, und davon auszugehen, dass der Tag "23" ist (oder eine Ausnahme auslösen, wenn beispielsweise "31" eingegeben wurde). Kann mir jemand die Details erklären?

+0

Ich bekomme, dass sie 23 bis 23 parsen, aber warum "Hunde" geparst zu "November 2015"? Und warum wird 23 als gültiges Datum geparst, 3 nicht? – Nzall

+0

Etwas an 'Date.parse()' zu erinnern ist, dass es nicht analysierbare Daten verwirft und alles analysiert, was noch übrig ist. Die "Hunde" haben keinen Einfluss auf das Ergebnis. Sie erhalten dasselbe, wenn Sie 'Date.parse ('23')' oder 'Date.parse ('23 cats ')' oder 'Date.parse ('23 Obamas')' versuchen. –

+0

Für ein weiteres Beispiel: 'irb (main): 006: 0> Date.parse ('Am 23. März habe ich 3 neue Hunde')' '==> # ' Das einzige, was in diesem Beispiel geparst wurde, war" 23 March " –

2

Also es hat nichts mit hebeln 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 Date#strptime für eine vorhersehbare Analyse von Datumsangaben in bekannten festen Formaten. Verwenden Sie das chronic Juwel für komplexere Analyse von Daten natürlicher Sprache in unvorhersehbaren Formaten.

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

Ich habe versucht, den MRI-Code für Date.parse zu betrachten, weil ich neugierig war, wenn ich herausfinden könnte, was es tat. 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 here, obwohl ich nicht den richtigen Ort für die aktuelle Version Implementierung gefunden haben könnte. 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 der jruby Code an die ich suchte (die nicht die aktuelle Implementierung sein könnte, ist aber einige Implementierung)

  • Schließlich, nach anderen potentiellen Parsen versuchen, die fehlschlagen, es versucht Date._parse_ddd - für beide Eingänge.

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

  • Wenn wir uns die Date._parse_ddd Implementierung ansehen ... 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, um herauszufinden, was los ist. 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"

mehr Update: Beachten Sie, dass Date.parse("03 dogs") analysiert statt zu erhöhen. 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 erfasst, aber ein falsches Datum könnte von einer der Möglichkeiten erwischt werden, die es schien gut genug, aber in diesem Fall war es falsch.

mehr Gedanken So ist es 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 zeitraubend ist, mit wenig Nutzen durch den Code zu gehen (wen interessiert das?), Wirst du wahrscheinlich niemanden dazu bringen, dies für dich zu tun.

+0

Ich habe mir die C angesehen Quelle auch, und kam nicht weiter.Wir brauchen jemanden, der damit vertraut ist, um durchzukommen und uns zu erzählen, was passiert. –

+0

Was mir aufgefallen ist, ist, dass aufgrund des Abstandes zwischen '23' und' Dogs' die zweite Fanggruppe tatsächlich 3 Zeichen lang ist, nicht 2. Ich bin mir nicht sicher, wie dies die Dinge verändert. Könnten Sie Date.parse ("23dogs") versuchen und sehen, welche Antwort Sie dann bekommen? – Nzall

+0

Ja, in der MRT gibt "23dogs" dasselbe Datumsobjekt wie "23 Dogs" zurück. –