# Regex für Zahleneingabe in JavaFX Textfield



## MarkusM (21. Jun 2014)

Hallo zusammen,

ich würde gerne die Eingabe von Zahlen in ein JavaFX TextField ermöglichen bzw. nur auf gültige Werte eingrenzen. Leider verrecke ich an der Regex-Geschichte.




```
s1.matches("^-?(?!0)(?:\\d+|\\d{1,3}(?:\\.\\d{3})+)$")
```

Dieses Regex bringt leider keinen Erfolg. Ich würde gerne die Eingabe von Zahlen, Tausendertrennzeichen und Dezimalkennzeichen erlauben - natürlich nur in dem korrekten Format!
Beispiel:

1.123.123,99
1123123,99
1.000
1000

nicht aber solche Geschichten wie:

1..2344,99
1..,,,123

Hat Hier jemand eine Idee? Im obigen Regex sind die Nachkommastellen und Dezimaltrennzeichen nicht vorhanden, dass ist klar, aber es funktioniert auch nicht mit ganzen Zahlen..... Obewohl es in der normalen Regex Pürfung im Internet tadellos klappt. 

Ich weiß echt nicht mehr weiter und hänge jtzt schon seit Tagen an dieser blöden Implementierung einer sinnvollen Zahlenerfassung in einem JavaFX Textfield (ich versteh nicht warum soetwas nicht zum Standard von JavaFX gehört, aber das ist ein anders Thema!).

Viele Grüße

Markus


----------



## MR_UNIX (21. Jun 2014)

Moin,

ich bin zwar sicherlich kein Regex-Experte, aber nach ein wenig basteln in einem Online Editor habe ich folgenden Regex für dich herausgefunden (deiner hat bei mir nicht wirklich funtkioniert): Regex

Kannst in dem unteren Eingabefeld ja mal den Text entsprechend ändern und schauen, ob er das passend matched. Im oberen Feld findest du die eigentliche Expression.


----------



## Ruzmanz (21. Jun 2014)

Da geht kein "1000" oder "1.000". Das ist ein 0815-Fall, dessen Lösung man im Internet locker finden kann. Das mit Regex zu lösen ist nicht ganz so einfach.


----------



## MarkusM (21. Jun 2014)

@MR_UNIX: Danke, das schaue ich mir morgen mal in Ruhe an!

@Ruzmanz: Wenn Du dafür eine Lösung hast, die man im Internet "locker" findet, sei doch so nett und spendiere mir mal einen Link.


----------



## java253 (22. Jun 2014)

```
^([\d]{1,3}(([\.][\d]{3})*|[\d]*)(,\d\d){0,1})$
```
ist mein Versuch.

Zum Beispiel zutreffend:
123.122.123,03
24.800.897
98544,23
6784125566

Nicht zutreffend:
678412.345
678.3453.234
678.345.234,767
678.345.234,7


----------



## MarkusM (22. Jun 2014)

Klappt alles nicht....

Das Problem liegt daran, dass sich der String bei der Eingabe zeichenweise aufbaut und so immer wieder ungültige Zeichenketten entstehen. Vielleicht bin ich mit meinem Ansatz auch grundsätzlich auf dem Holzweg.

Hat vielleicht jemand eine Idee wie ich ein JavaFX Textfield zu umbauen kann, dass nur die Eingabe von Zahlenwerten (optional mit Komma und Punkt) möglich sind? Mein aktueller Weg geht über einen ChangeListener der textProperty, aber der scheint nicht wirklich von Erfolg gekröhnt zu sein.

Bin wirklich für jede Idee dankbar, denn so langsam verliere ich echt die Lust. Ein Textfeld mit Validierung für Zahleneingaben kann doch kein Hexenwerk sein.....

Viele Grüße

Markus


----------



## java253 (22. Jun 2014)

Was klappt nicht? Du musst in Java innerhalb von Strings \\ verwenden, um einen Backslash zu erzeugen.

```
Pattern p = Pattern.compile("^([\\d]{1,3}(([\\.][\\d]{3})*|[\\d]*)(,\\d\\d){0,1})$");
Matcher m = p.matcher("160.200,30");
System.out.println(m.find());
```


----------



## Ruzmanz (22. Jun 2014)

Google: "Regex Number Format". Evtl. hilft auch der erste Link, aber das war mir zu blöd, weil das schlecht erklärt wurde. Also habe ich mir den zweiten Link angeschaut ... viel einfacher.


```
((?<=\s)|^)[-+]?((\d{1,3}([,\s.']\d{3})*)|\d+)([.,/-]\d+)?((?=\s)|$)
```

Was fällt auf? Die geposteten Lösungen sind 0 durchdacht. Klar kann man da noch einfach ein Minuszeichen ergänzen ... Im ursprünglichen Regex ist zumindest ein "-" zu erkennen. Aber wenn man sich die Beispiele anguckt, kommt man nur auf positive, deutsche Zahlen mit zwei Nachkommastellen. Sicher nur positiv? Sicher nur zweistellige Nachkommastellen? Sicher nur deutsches Format? ...

Positiv/Negativ - Mit/Ohne Trennzeichen - Mit/Ohne Nachkommastellen - unbegrenzte Nachkomma (kannst du anpassen) - deutsches Zahlenformat - In Java:


```
((?<=\\s)|^)[-+]?((\\d{1,3}([\\.]\\d{3})*)|\\d+)([,]\\d+)?((?=\\s)|$)
```

1min googeln - 5min anpassen/sporadisch testen ...


----------



## java253 (22. Jun 2014)

Ruzmanz hat gesagt.:


> ```
> ((?<=\s)|^)[-+]?((\d{1,3}([,\s.']\d{3})*)|\d+)([.,/-]\d+)?((?=\s)|$)
> ```
> 
> Was fällt auf? Die geposteten Lösungen sind 0 durchdacht.




Auf www.regexpal.com funktioniert das nicht, in Java allerdings doch.

Meine Lösung:

Negative Zahlen:

```
^[-]?([\d]{1,3}(([\.][\d]{3})*|[\d]*)(,\d\d)?)$
```

und beliebig viele Nachkommastellen:

```
^[-]?([\d]{1,3}(([\.][\d]{3})*|[\d]*)(,\d+)?)$
```


----------



## Ruzmanz (22. Jun 2014)

Probiers in Java aus. Ich habe den Ausdruck 
	
	
	
	





```
((?<=\s)|^)
```
 ... 
	
	
	
	





```
((?=\s)|$)
```
 selbst noch nie gesehen, um eine Boundaries festzulegen. Fakt ist, dass der Java-Compiler das interpretieren kann. Sonst musst du es wahrscheinlich mit 
	
	
	
	





```
\b[-+]?((\d{1,3}([,\s.']\d{3})*)|\d+)([.,/-]\d+)?\b
```
 probieren ... Keine Ahnung wieso du glaubst, dass ich betrunken bin. Die Lösung ist nicht von mir, die Quelle angegeben und von mir/anderen bereits getestet.

PS: Jetzt müsste dein Ergebnis stimmen.


----------



## java253 (22. Jun 2014)

Ich hatte die Regex auf www.regexpal.com getestet, dort funktioniert sie absolut nicht. In Java funktioniert sie aber fast. Deine findet z.B: "5.5", "5,566,45327" und "50.568.83745". Betrunken nehme ich zurück.


----------



## MarkusM (22. Jun 2014)

@ruzmanz: Das Regex funktioniert sofern ich einen ganzen String benutze. Bei meinem Textfeld habe ich allerdings das Problem, dass die Zeichen ja einzeln, nacheinander eingegeben und mit jeweils dem Regex auf Gültigkeit überprüft werden. Passt das Regex nicht wird das Zeichen abgewiesen.

D.h. wenn ich beispielsweise die Zahl 1.000 erfassen möchte, dann wird nach der "1" der "." nicht akzeptiert. Ich überlege gerade, ob ich die Eingabe des Strings nicht zeichenweise sondern bei Fokusverlust mit dem Regex überprüfe.

Ich wusel mich da noch etwas durch, aber tausend Dank für Eure Hinweise! Falls jemand eine andere Lösung für ein solches Textfeld hat, nur her damit....

Viele Grüße

Markus


----------



## java253 (22. Jun 2014)

Verständnisfrage:
Heißt das, dass alles zutreffen soll, was noch durch anhängen von Zeichen zu einer gültigen Zahl werden kann?
Z. B. "5.", "5.033.4", "-34.344,", aber nicht: "5.3.", ".43", "3.224.,".


Zweiter Versuch:
Regex:

```
^[-]?(([\d]{1,3}(\.\d{3})*(((\,\d{0,})?|(\.\d{0,3}))?)|(\d*(\,\d{0,})?))?)$
```


```
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class PatternTest{
	public static void main(String[] args){
		String[] tests = {"1000,", "-", "-557600", "", "44.220.24", "56.23", "82.2", "823.245,2565", "-752.234,", "7855.", "82.2582.223", "8,,2", "86..005", "10.43,23"};
		Pattern p = Pattern.compile("^[-]?(([\\d]{1,3}(\\.\\d{3})*(((\\,\\d{0,})?|(\\.\\d{0,3}))?)|(\\d*(\\,\\d{0,})?))?)$");
		for(int i = 0; i < tests.length; i++) {
			Matcher m = p.matcher(tests[i]);
			System.out.println(tests[i] + ":" + m.matches());
		}
	}
}
```
Ausgabe:
1000,:true
-:true
-557600:true
:true
44.220.24:true
56.23:true
82.2:true
823.245,2565:true
-752.234,:true
7855.:false
82.2582.223:false
8,,2:false
86..005:false
10.43,23:false


----------



## Ruzmanz (22. Jun 2014)

> D.h. wenn ich beispielsweise die Zahl 1.000 erfassen möchte, dann wird nach der "1" der "." nicht akzeptiert. Ich überlege gerade, ob ich die Eingabe des Strings nicht zeichenweise sondern bei Fokusverlust mit dem Regex überprüfe.



Hast du richtig erkannt. Man kann das nicht Just-In-Time lösen, da "1." gültig ist, sofern man noch drei Zahlen drannhängt. Du kannst Just-In-Time prüfen, ob die Länge eingehalten wird (max. 7 Vorkomma, max. 2 Nachkomma), ob die Zeichen korrekt sind (max. 1 Plus/Minus, max. 2 Punkte bei 7 Vorkomma, max. 1 Komma bei Dezimalzahlen, nur Vorzeichen/Ziffern/Komma/Punkte akzeptieren) und ob das Vorzeichen an vorderster Stelle steht.

Du kannst bei Fokusverlust prüfen, ob die Dezimalzahl (7 Vorkomma, 2 Nachkomma, mit Vorzeichen) auch gültig eingetippt wurde: "7..1,00" -> falsch // "7001,00" -> richtig.

Du kannst bei Fokusverlust automatisch korrigieren: Format einheitlich halten, indem Nachkomma ergänzt werden. Bsp. "201" wird zu "201,00". Oder Tausenderzeichen ergänzt werden. Bsp. "1000,00" wird zu "1.000,00". Sichtlich ungültige Formate sollte man nicht anpassen. Bsp. "7..1,00" zu "71,00".

Sofern das Format bei Fokusverlust ungültig ist -> verwerfen.

Benutzerfreundlicher ist es zudem, wenn du beim Fokus die Zahlen wieder ohne Tausenderpunkte darstellst, sodass aus "100.342.203,00" -> "100342203,00" wird.

PS: Wenn per Default "0,00" in den Textfeldern steht (bei Dezimaltahlen mit 2 Nachkommastellen) kann man das Komma und die Nachkommastellen auch Just-In-Time überwachen.


----------



## MarkusM (22. Jun 2014)

So, ich hab das Ganze jetzt im Grundgerüst hinbekommen.

Die Eingabezeichen sind beschränkt auf 0-9,.+-
Bei Fokusverlust per Regex geprüft, ob es eine Zahl ist.


```
getText().matches("[-+]?((\\d{1,3}([\\.]\\d{3})*)|\\d+)([,]\\d+)?")
```

Wenn ok, dann Formatierung der Zahl in einheitliches Format (z.B. 1000,12 => 1.000,12) ansonsten roter Rahmen, alles Auswählen und Fokus bleibt im Feld => valide Eingabe wird erzwungen.

Erhält das Zahlenfeld den Focus, werden die Tausendertrennzeichen entfernt um die Eingabe komfortabel zu gestalten.

Was mir noch nicht ganz gefällt ist die Formatierung der Zahlen. Dies habe ich wie folgt gelöst:


```
DecimalFormat df = new DecimalFormat("###,##0.00");
String string;
string = getText();
string = string.replace(".","");
string = string.replace(",",".");
setText(df.format(Double.parseDouble(string)));
```

Hier gibt es doch sicherlich einen eleganteren Weg, als das Ersetzen der Zeichen um den String in ein Double umwandeln zu können?

@ruzmanz


> PS: Wenn per Default "0,00" in den Textfeldern steht (bei Dezimaltahlen mit 2 Nachkommastellen) kann man das Komma und die Nachkommastellen auch Just-In-Time überwachen.



Ich steh mit dem Regex zur Zeit nch echt auf dem Kriegsfuss, hast Du hier vielleicht noch einen Ansatz für mich, wie Du soetwas bewerkstelligst?

Viele Grüße

Markus


----------



## Ruzmanz (22. Jun 2014)

> Wenn ok, dann Formatierung der Zahl in einheitliches Format (z.B. 1000,12 => 1.000,12) ansonsten roter Rahmen, alles Auswählen und Fokus bleibt im Feld => valide Eingabe wird erzwungen.



Klingt nicht sehr benutzerfreundlich. Solange sich ein ungültiger Input im Textfeld befindet -> Roter Rahmen. Solange sich ein gültiger Input befindet -> Gründer Rahmen. Beim Verlassen -> Reset. Kenne genug Leute, die von einem Chaos ins nächste stürzen ... bzw. unbewusst etwas ändern.



> Ich steh mit dem Regex zur Zeit nch echt auf dem Kriegsfuss, hast Du hier vielleicht noch einen Ansatz für mich, wie Du soetwas bewerkstelligst?



Das geht mit Regex nicht. Mögliche Implementierung:

- Fokus bei "0,00": Die erste "0" wird markiert. "0,00", sodass der Benutzer gleich lostippen kann.

- Befindet sich der Cursor vor dem Komma und tippt der Benutzer ein Komma, dann springt der Cursor eine Position weiter. Beispiel: "100|,00" -> tippt "," -> "100,|00". Versucht der Benutzer ein weiteres Komma zu setzen wird die Eingabe ignoriert.

- Befindet sich der Cursor nach dem Komma und tippt der Benutzer eine Zahl, entfällt die letzte Stelle. Dies ist nur der Fall, sofern die letzte Stelle eine "0" ist. Ansonsten blockiert die Eingabe.
"100,|00" -> tippt "1" -> "100,1|0"
"100,|01" -> tippt "2" -> "100,|01"

- Versucht der Benutzer die Eingabe durch einen String s < 4 zu ersetzen, muss der Input validiert werden. Je nach Ergebnis wird ersetzt oder blockiert.

- Gibt noch ein paar Regeln ... lohnt sich jetzt nicht alles aufzulisten, wenn du es am Ende nicht umsetzen willst.


----------



## MarkusM (22. Jun 2014)

Deine Tipps sind für mich echt hilfreich und ich bin für weiteren Input immer dankbar! Ich versuche möglichst viel umzusetzen, um mir ein möglichst umfangreiches TextField für Zahlenwert zu bauen. Ob ich alles schaffe steht auf einem anderen Blatt, aber mein Ziel ist es auf jeden Fall eine ordentliche Umsetzung zu schaffen, die ich vielfältig einsetzen kann. Daher bin ich für Input und auch Erfahrungswerte mehr als dankbar.

Das der Fokus nicht weiterspringt bei invaliden Werten finde ich jetzt nicht so benutzerunfreundlich, werde aber Deine Variante auch mal testen. Ich habe zur Zeit auch noch das "Problem", dass das Textfeld an ein Bean gebunden ist und somit invalide Werte (String => Double) ziemlich übel sind.

Wenn Du noch die Muße und Geduld hast, dann bin ich ehrlich neugierig auf Deine weiteren Regeln.

Viele Grüße

Markus


----------



## Ruzmanz (23. Jun 2014)

Fokus bekommen:


Zahl speichern.
Tausenderpunkte entfernen.
Bei „0,00“ -> „ 0|,00“
Bei „1.234,56“ -> „1234,56|“
(Alternativ: Bei „0,12“ -> „0,12|“ //  Bei „1.234,00“ -> „1234|,00“)

Zeichen wird gesetzt:
Überspringen:

Komma: Falls sich der Cursor vor dem Komma befindet, dann springt diese eine Position weiter:
"100|,00" -> tippt "," -> "100,|00"
Punkt:  Falls sich der Cursor vor einem Punkt befindet, dann springt diese eine Position weiter:
"1|.100,00" -> tippt "." -> "1.|100, 00"
Minus:  Sofern sich ein „-“ an erster Stelle befindet, Position überspringen:
„|-100,00“ -> tippt „-“ -> „-|100,00“

Blockieren:

Ziffer: Anzahl der Ziffern vor / nach dem Komma beschränken, indem Eingaben blockiert werden.
(3 Vorkomma) „123|,00“ -> tippt „4“ -> „123|,00“
(3 Vorkomma) „123|,00“ -> tippt „4“ -> „124|,00“
Ziffer: Kann nicht gesetzt werden, sofern sich der Cursor vor einem Minus befindet. (keine automatische Korrektur):
„|-100,00“ -> tippt „2“ -> „|-100,00“
!Ziffer: Blockieren, sofern es sich nicht um ein Komma/Punkt/Minus/Plus handelt.
Komma: Blockieren falls Anzahl > 1
Punkt: Blockieren sofern es sich um die nullte Position handelt oder nicht die jeweils „dritte“ Position ist: 
"1|100,00" -> tippt "." -> "1.|100,00"
"11|00,00" -> tippt "." -> "11|00,00"
"|100,00" -> tippt "." -> "|100,00"
C&P: Blockieren, falls Zeichen(kette) durch ungültigen Input wird ersetzt wird:
„1|,23“ -> Paste „abc“ -> „1|,23“
(im Zweifel blockieren, da sehr viele Kombinationen möglich sind. Siehe automatische Korrektur.)
Minus: Blockieren, sofern sich der Cursor nicht an der ersten Position befindet.
„|100,00“ -> tippt „-“ -> „-|100,00“
„1|00,00“ -> tippt „-“ -> „1|00,00“

Automatische Korrektur:

Ziffer: Automatische Korrektur bei Nachkommastellen, sofern sich am Ende eine „0“ befindet:
(2 Nachkomma) „123,|00“ -> tippt „4“ -> „123,40|0“ -> „123,4|0“
(2 Nachkomma) „123,|01“ -> tippt „4“ -> „123,|01“
Ziffer: Tausenderpunkte automatisch korrigieren [durch entfernen oder weiterschieben, wobei letzteres irritierend wirken kann] (nur sofern gesetzt).
"1.1|00,00" -> tippt "2" -> "112|00,00"
Plus: Sofern sich ein „-“ an erster Stelle befindet, löschen:
„|-100,00“ -> tippt „+“ -> „|100,00“
Plus: Sofern sich ein „+“ an erster Stelle befindet, löschen. Eingabe nicht blockieren. Es sind zwar fehlerhafte Eingaben möglich, aber eher uninteressant: „674,34|“ -> Paste „+-100,00“ -> „-100,00|“
„|100,00“ -> tippt „+“ -> „|100,00“
Zeichen(kette) wird durch eine Aktion entfernt (Korrektur Tausenderpunkte, Korrektur Nachkomma, Korrektur Vorzeichen)“:
„10.000|,00“ -> entfernen -> „100|,00“
„10.000,00|“ -> ersetzen durch „1.234“ -> „1.234,00|“
„10.000,00|“ -> ersetzen durch „1.234,5“ -> „1.234,50|“
„-10.000,00|“ -> ersetzen durch „-1.234,5“ -> „-1.234,5|“ (Doppeltes Minus)
„-10.000,00|“ -> ersetzen durch „+1.234,5“ -> „1.234,5|“ (-+)
„10,00|“ ->löschen -> „0|,00“ (-+)
„|0,00“ -> tippt Entf -> „0|,00“ (umgekehrte Logik für löschen)
„0|,00“ -> tippt Entf -> „0,|00“ (umgekehrte Logik für löschen)
„1,|23“ -> tippt Entf -> „1,|30“ (umgekehrte Logik für löschen)
„1,2|3“ -> tippt Entf -> „1,20|“ (umgekehrte Logik für löschen)
„0|,00“ bzw. „0,00|“ -> tippt „-“ -> „-0|,00“
„0|,00“ -> tippt „+“ -> „0|,00“
Komma: Wird der Zustand „,00“ erzeugt, springt der Cursor hinter das Komma und setzt eine „0“ an den Anfang.
„100|,00“ -> tippt „,“ -> „0,|00“
„0,00|“ -> tippt „,“ -> „0,|00“

Validierung:

Nach jeder Eingabe müsste der Input korrekt sein (, sofern ich nichts übersehen habe und setText etc. dementsprechend abgesichert sind). Zuerst den Inhalt manuell formatieren („1.223123,00“ -> „1.223.123,00“) und dann mit deinem Regex überprüfen. Bei Fehlern auf den zuvor gespeicherten Wert zurücksetzen + Loggen, um die Lücke zu schließen ). Den visuellen / tatsächlichen Inhalt aber nicht durch den formatieren Wert ersetzen.

Fokus verloren:

Manuell formatieren und Text durch diesen ersetzen.

Was ich unter anderem auch schon gesehen habe, ist dass man die manuell eingetippten Tausenderpunkte hellgrau hinterlegt und sobald der Input gültig wird, werden diese schwarz angezeigt. Gibt sicherlich noch Tausend andere Möglichkeiten, welche letztendlich vom Nutzer und dem Format abhängen.


> Ich habe zur Zeit auch noch das "Problem", dass das Textfeld an ein Bean gebunden ist und somit invalide Werte (String => Double) ziemlich übel sind.


Ich würde das an den zuletzt gespeicherten (== gültigen Wert) koppeln und nicht an den Text.

PS: JUnit-Test*s* nicht "vergessen" opcorn:


----------



## MarkusM (23. Jun 2014)

@ruzmanz: Tausend Dank für Deine Mühen!!! :toll::toll::toll:

Dann habe ich jetzt was zu tun!

Viele Grüße

Markus


----------

