Ich versuche, alle Zahlen in einem Textkörper zu finden und zu ersetzen. Ich habe ein paar Regex-Beispiele gefunden, die das Problem fast lösen, aber noch keine sind perfekt. Das Problem, das ich habe, ist, dass die Zahlen in meinem Text Dezimalstellen und Kommas haben können oder nicht. Beispielsweise:
"Der 5000 Pfund schwere Fuchs sprang über einen 99.999.99998713 Fußzaun."
Die Regex sollte " 5000
" und " 99,999.99998713
" zurückgeben. Beispiele Ich habe festgestellt, dass die Zahlen im Komma aufgelöst sind oder auf zwei Dezimalstellen beschränkt sind. Ich fange an, Regex genug zu verstehen, um zu verstehen, warum einige Beispiele auf zwei Dezimalstellen beschränkt sind, aber ich habe noch nicht gelernt, wie man sie überwindet und auch das Komma einfügt, um die gesamte Sequenz zu erhalten.
Hier ist meine neueste Version:
[0-9]+(\.[0-9][0-9]?)?
Was für den obigen Text " 5000
", " 99,99
", " 9.99
" und " 998713
" zurückgibt .
.,.,.
oder9,9,9,9
oder zuzulassen9,9.99.9
. Diese regulären Ausdrücke erfordern nicht, dass Zahlen im richtigen Format vorliegen, und behandeln Interpunktion im schlimmsten Fall als Zahlen. Es sind einige optionale Optimierungen möglich (z. B. ob führende und nachfolgende Nullen zulässig sind), aber einige der Antworten, die ich sehe, sind geradezu falsch. Ich mag Downvoting wirklich nicht, besonders bei ehrlichen Versuchen, aber ich denke, die Antworten hier müssen aufgeräumt werden. Dies ist eine häufige Frage und wird auf jeden Fall erneut gestellt.Antworten:
EDIT: Da dies viele Ansichten bekommen hat, lassen Sie mich damit beginnen, allen zu geben, wonach sie gegoogelt haben:
Nun, da dies nicht im Weg ist, sind die meisten der folgenden Punkte als Kommentar dazu gedacht, wie komplex Regex werden kann, wenn Sie versuchen, klug damit umzugehen, und warum Sie nach Alternativen suchen sollten. Lesen Sie auf eigenes Risiko.
Dies ist eine sehr häufige Aufgabe, aber alle Antworten , die ich hier sehen , so weit werden Eingänge akzeptieren , die, wie Sie nicht Ihre Nummer Format entsprechen
,111
,9,9,9
oder sogar.,,.
. Das ist einfach zu beheben, selbst wenn die Zahlen in anderen Text eingebettet sind. IMHO alles, was nicht 1.234,56 und 1234 - und nur diese Zahlen - herausziehen kannabc22 1,234.56 9.9.9.9 def 1234
eine falsche Antwort.Wenn Sie dies nicht alles in einem regulären Ausdruck tun müssen, tun Sie dies zunächst nicht. Eine einzelne Regex für zwei verschiedene Zahlenformate ist schwer zu pflegen, selbst wenn sie nicht in anderen Text eingebettet sind. Was Sie wirklich tun sollten, ist, das Ganze auf Leerzeichen aufzuteilen und dann zwei oder drei kleinere reguläre Ausdrücke für die Ergebnisse auszuführen. Wenn dies für Sie keine Option ist, lesen Sie weiter.
Grundverhalten
In Anbetracht der Beispiele, die Sie gegeben haben, ist hier eine einfache Regex, die so ziemlich jede Ganzzahl oder Dezimalzahl im
0000
Format zulässt und alles andere blockiert:Hier ist eines, das
0,000
Format erfordert :Fügen Sie sie zusammen und Kommas werden optional, solange sie konsistent sind:
Eingebettete Zahlen
Für die obigen Muster muss die gesamte Eingabe eine Zahl sein. Sie suchen nach Zahlen, die in Text eingebettet sind, also müssen Sie diesen Teil lösen. Auf der anderen Seite möchten Sie nicht, dass es
catch22
die Nummer 22 sieht und denkt, dass es gefunden wurde. Wenn Sie etwas mit Lookbehind-Unterstützung (wie .NET) verwenden, ist dies ziemlich einfach: Ersetzen Sie es^
durch(?<!\S)
und$
mit(?!\S)
und Sie sind gut gehen:Wenn Sie mit JavaScript oder Ruby oder etwas anderem arbeiten, sehen die Dinge komplexer aus:
Sie müssen Erfassungsgruppen verwenden. Ich kann mir keine Alternative ohne Lookbehind-Unterstützung vorstellen. Die gewünschten Zahlen befinden sich in Gruppe 1 (vorausgesetzt, die gesamte Übereinstimmung ist Gruppe 0).
Validierung und komplexere Regeln
Ich denke, das deckt Ihre Frage ab. Wenn das alles ist, was Sie brauchen, hören Sie jetzt auf zu lesen. Wenn Sie schicker werden möchten, werden die Dinge sehr schnell sehr komplex. Abhängig von Ihrer Situation möchten Sie möglicherweise einige oder alle der folgenden Elemente blockieren:
Nehmen wir zum Teufel an, Sie möchten die ersten 3 blockieren, aber die letzte zulassen. Was tun? Ich werde Ihnen sagen, was Sie tun sollten. Sie sollten für jede Regel einen anderen regulären Ausdruck verwenden und Ihre Übereinstimmungen schrittweise eingrenzen. Aber um der Herausforderung willen, machen Sie Folgendes in einem riesigen Muster:
Und hier ist was es bedeutet:
Hier getestet: http://rextester.com/YPG96786
Dies ermöglicht Dinge wie:
Es wird Dinge blockieren wie:
Es gibt verschiedene Möglichkeiten, diesen regulären Ausdruck einfacher und kürzer zu gestalten. Verstehen Sie jedoch, dass durch Ändern des Musters das, was es als Zahl betrachtet, gelockert wird.
Da viele Regex-Engines (z. B. JavaScript und Ruby) das negative Lookbehind nicht unterstützen, können Sie dies nur mit Erfassungsgruppen korrekt tun:
Die gesuchten Nummern befinden sich in Erfassungsgruppe 1.
Hier getestet: http://rubular.com/r/3HCSkndzhT
Eine letzte Anmerkung
Offensichtlich ist dies eine massive, komplizierte, nahezu unlesbare Regex. Ich habe die Herausforderung genossen, aber Sie sollten überlegen, ob Sie dies wirklich in einer Produktionsumgebung verwenden möchten. Anstatt zu versuchen, alles in einem Schritt zu tun, können Sie es in zwei Schritten tun: eine Regex, um alles zu fangen, was eine Zahl sein könnte , und eine andere, um alles auszusortieren, was keine Zahl ist. Oder Sie können eine grundlegende Verarbeitung durchführen und dann die in Ihrer Sprache integrierten Funktionen zum Parsen von Zahlen verwenden. Deine Entscheidung.
quelle
Vor einigen Tagen habe ich an dem Problem gearbeitet, nachgestellte Nullen aus der Zeichenfolge einer Zahl zu entfernen .
In der Kontinuität dieses Problems finde ich dieses interessant, weil es das Problem auf Zahlen erweitert, die Kommas enthalten.
Ich habe das Muster des regulären Ausdrucks, das ich in dem vorherigen Problem geschrieben habe, an dem ich gearbeitet habe, übernommen und es verbessert, damit die Zahlen als Antwort auf dieses Problem mit Kommas behandelt werden können.
Ich bin von meiner Begeisterung und meiner Vorliebe für Regexes mitgerissen worden. Ich weiß nicht, ob das Ergebnis genau zu dem von Michael Prescott geäußerten Bedarf passt. Es würde mich interessieren, welche Punkte in meinem regulären Ausdruck zu viel oder zu wenig vorhanden sind, und ihn zu korrigieren, um ihn für Sie besser geeignet zu machen.
Jetzt, nach einer langen Arbeitssitzung an diesem regulären Ausdruck, habe ich eine Art Gewicht im Gehirn, daher bin ich nicht frisch genug, um viele Erklärungen abzugeben. Wenn Punkte dunkel sind und jemand interessiert genug sein könnte, fragen Sie mich bitte.
Der Regex ist so aufgebaut, dass er die in der wissenschaftlichen Notation 2E10 oder sogar 5,22,454.12E-00.0478 ausgedrückten Zahlen erkennen kann , wobei auch unnötige Nullen in den beiden Teilen solcher Zahlen entfernt werden. Wenn ein Exponent gleich Null ist, wird die Zahl so geändert, dass kein Exponent mehr vorhanden ist.
Ich habe das Muster überprüft, damit einige bestimmte Fälle nicht übereinstimmen, zum Beispiel '12 ..57 ' nicht. Aber in ', 111' die Zeichenfolge '111' stimmt überein, da das vorhergehende Komma als Komma betrachtet wird, das nicht in einer Zahl, sondern als Komma eines Satzes steht.
Ich denke, dass die Verwaltung von Kommas verbessert werden sollte, da es meiner Meinung nach nur zwei Ziffern zwischen Kommas in der indischen Nummerierung gibt. Es wird nicht schwer zu korrigieren sein, nehme ich an
Hier ist ein Code, der zeigt, wie meine Regex funktioniert. Es gibt zwei Funktionen, je nachdem, ob die Zahlen '.1245' in '0.1245' transformiert werden sollen oder nicht. Es würde mich nicht wundern, wenn Fehler oder unerwünschte Übereinstimmungen oder Nichtübereinstimmungen für bestimmte Fälle von Zahlenfolgen bestehen bleiben. dann möchte ich diese Fälle kennen, um den Mangel zu verstehen und zu korrigieren.
Ich entschuldige mich für diesen in Python geschriebenen Code, aber Regexes sind trans-langage und ich denke, jeder wird in der Lage sein, das Muster des Reex zu verstehen
Ergebnis
quelle
Die Regex unten entspricht beiden Zahlen aus Ihrem Beispiel.
Es werden 5000 und 99.999.99998713 zurückgegeben - entsprechend Ihren Anforderungen.
quelle
this,that
.\b\d[\d,.]+\b
9....9
oder1,,,,X
(obwohl das X nicht im Match enthalten sein wird).\b\d[\d,.]*\b
ist nah genug, dass ich die -1 entfernen werde, wenn Sie Ihre Antwort bearbeiten. Es sollte jedoch ein * anstelle eines + sein.\b\d[\d,.]+\b
lässt keine einstelligen Zahlen zu.Nehmen Sie sich eine gewisse Freiheit mit den Anforderungen, die Sie suchen
Beachten Sie jedoch, dass dies z. B. 11,11,1 entspricht
quelle
\d+([\d,]?\d)*(\.\d+)?
statt\d+(,\d+)*(\.\d+)?
? Ich denke, sie würden gleichwertige Übereinstimmungen geben, obwohl die Erfassungsgruppen unterschiedlich wären.Dies setzt voraus, dass vor oder nach einem Komma oder einer Dezimalstelle immer mindestens eine Ziffer steht, und setzt voraus, dass höchstens eine Dezimalstelle vorhanden ist und dass alle Kommas vor der Dezimalstelle stehen.
quelle
999999,9,9,9,9
.(,\d+)
zu(,\d\d\d)
Ich denke.Diese Regex:
Stimmt mit jeder Zahl in der Zeichenfolge überein:
1 1,0 0,1 1,001 1.000 1.000.000 1000,1 1.000,1 1.323.444.000 1.999 1.222.455.666,0 1.244
quelle
Hier ist eine Regex:
das akzeptiert Zahlen:
123456789
,123.123
123 456 789
,123 456 789.100
,123,456
,3,232,300,000.00
Tests: http://regexr.com/3h1a2
quelle
Hier ist eine weitere Konstruktion, die mit dem einfachsten Zahlenformat beginnt und dann auf nicht überlappende Weise zunehmend komplexere Zahlenformate hinzufügt:
Java-Regep:
Als Java-Zeichenfolge (beachten Sie, dass das zusätzliche \, das benötigt wird, um nach \ und. Zu maskieren, da \ und. Allein in einem regulären Ausdruck eine besondere Bedeutung haben):
Erläuterung:
Dieser reguläre Ausdruck hat die Form A | B | C | D | E | F, wobei A, B, C, D, E, F selbst reguläre Ausdrucke sind, die sich nicht überlappen. Im Allgemeinen fällt es mir leichter, mit den einfachsten Übereinstimmungen A zu beginnen. Wenn A die gewünschten Übereinstimmungen verfehlt, erstellen Sie ein B, das eine geringfügige Änderung von A darstellt und etwas mehr von dem enthält, was Sie möchten. Erstellen Sie dann basierend auf B ein C, das mehr fängt usw. Ich finde es auch einfacher, reguläre Ausdrücke zu erstellen, die sich nicht überlappen. Es ist einfacher, einen regulären Ausdruck mit 20 einfachen, nicht überlappenden regulären Ausdrücken zu verstehen, die mit OPs verbunden sind, als einige reguläre Ausdrücke mit komplexeren Übereinstimmungen. Aber jeder für sich!
A ist (\ d) und entspricht genau einem von 0,1,2,3,4,5,6,7,8,9, was nicht einfacher sein kann!
B ist ([1-9] \ d +) und stimmt nur mit Zahlen mit 2 oder mehr Ziffern überein, wobei die erste 0 ausschließt. B entspricht genau einem von 10,11,12, ... B überlappt A nicht, ist aber eine kleine Modifikation von A.
C ist (. \ D +) und entspricht nur einer Dezimalstelle, gefolgt von einer oder mehreren Ziffern. C entspricht genau einem von .0 .1 .2 .3 .4 .5 .6 .7 .8 .9 .00 .01 .02 .... .23000 ... C erlaubt rechts ablaufende Eros, was ich bevorzuge: Wenn es sich um Messdaten handelt, gibt die Anzahl der nachgestellten Nullen die Genauigkeit an. Wenn Sie die nachgestellten Nullen rechts nicht möchten, ändern Sie (. \ D +) in (. \ D * [1-9]), aber dies schließt auch .0 aus, was meiner Meinung nach zulässig sein sollte. C ist auch eine kleine Modifikation von A.
D ist (\ d. \ D *), was A plus Dezimalstellen mit nachgestellten Nullen rechts ist. D entspricht nur einer einzelnen Ziffer, gefolgt von einer Dezimalstelle, gefolgt von null oder mehr Ziffern. D entspricht 0. 0.0 0.1 0.2 .... 0.01000 ... 9. 9.0 9.1..0.0230000 .... 9.9999999999 ... Wenn Sie "0" ausschließen möchten. Ändern Sie dann D in (\ d. \ d +). Wenn Sie rechts abschließende Nullen ausschließen möchten, ändern Sie D in (\ d. \ D * [1-9]), aber dies schließt 2.0 aus, was meiner Meinung nach enthalten sein sollte. D überlappt A, B oder C nicht.
E ist ([1-9] \ d +. \ D *), was B plus Dezimalstellen mit nachgestellten Nullen rechts ist. Wenn Sie beispielsweise "13" ausschließen möchten, ändern Sie E in ([1-9] \ d +. \ D +). E überlappt A, B, C oder D. E stimmt nicht mit 10. 10.0 10.0100 .... 99.9999999999 ... Nachgestellte Nullen können wie in 4. und 5 behandelt werden.
F ist ([1-9] \ d {0,2} (, \ d {3}) + (. \ D *)?) Und stimmt nur mit Kommas und möglicherweise Dezimalstellen überein, die rechts nachgestellte Nullen zulassen. Die erste Gruppe ([1-9] \ d {0,2}) stimmt mit einer Ziffer ungleich Null überein, gefolgt von null, einer oder zwei weiteren Ziffern. Die zweite Gruppe (, \ d {3}) + entspricht einer 4-stelligen Gruppe (ein Komma gefolgt von genau drei Ziffern) und diese Gruppe kann ein- oder mehrmals übereinstimmen (keine Übereinstimmungen bedeuten keine Kommas!). Schließlich (. \ D *)? passt nichts oder passt. für sich oder entspricht einer Dezimalstelle. gefolgt von einer beliebigen Anzahl von Ziffern, möglicherweise keiner. Um Dinge wie "1.111." Auszuschließen, ändern Sie (. \ D *) in (. \ D +). Nachgestellte Nullen können wie in 4. oder 5 behandelt werden. F überlappt A, B, C, D oder E nicht. Ich könnte mir keinen einfacheren regulären Ausdruck für F vorstellen.
Lassen Sie mich wissen, wenn Sie interessiert sind, und ich kann oben bearbeiten, um die nachfolgenden Nullen auf der rechten Seite wie gewünscht zu behandeln.
Folgendes passt zu regulärem Ausdruck und was nicht:
quelle
\ b -------> Wortgrenze
\ d + ------> eine oder eine Ziffer
, --------> mit Kommas,
Z.B:
sddsgg 70.000 sdsfdsf fdgfdg70,00
sfsfsd 5,44,4343 5,7788,44 555
Es wird passen:
70,
5,
44,
44
quelle
Dies würde mit jeder kleinen oder großen Zahl wie folgt mit oder ohne Komma übereinstimmen
oder
quelle