Regex: Zahl ohne führende Null

  • Themenstarter Themenstarter Camino
  • Beginndatum Beginndatum
C

Camino

Gast
Hallo,

ich bin nun schon seit einiger Zeit am Suchen und Grübeln nach einer Regular Expression, komme aber nicht weiter. Hört sich eigentlich nicht so kompliziert an:
ich bräuchte ein Pattern für eine Zahl, die nicht mit einer Null beginnen darf. Die Zahl darf eigentlich auch nicht komplett aus Nullen bestehen, oder mehrere Nullen am Anfang haben, aber das wäre ja mit der Überprüfung auf 1 führende Null erledigt. Das Pattern habe ich in einem DocumentFilter, welcher an einem JTextField hängt. Es soll also schon bei der Eingabe ins Textfeld verhindert werden, dass als erstes eine Null eingegeben werden kann.

Irgendwie ist mir die Funktionsweise der Regex noch nicht so ganz klar.
Die Ziffern von 0-1 kann ich ja mit [0-9]+ matchen. Keine Null ist wohl [^0]. Aber wie bringe ich die jetzt zusammen, und so, dass in der Zahl keine Null am Anfang stehen darf?

Gruss
Camino
 
Vllt sowas wie
Code:
[1-9]{1}\d*
Nachtrag: du kannst auch überprüfen, ob am anfang eine 0 steht:
Code:
0\d*
, je nach dem welche Logik du haben willst
 
Zuletzt bearbeitet:
Hmm, wenn ich meinen Pattern-String so schreibe:
"[1-9]{1}\d*"
dann bekomme ich in Eclipse die Fehlermeldung:
Invalid escape sequence (valid ones are \b \t \n \f \r \" \' \\ )

Dachte halt, ich muss das Steuerzeichen evtl. auch noch escapen. Wenn ich es so schreibe:
"[1-9]{1}\\d*"
dann ist die Fehlermeldung weg, ich kann dann aber in das Textfeld gar keine Nullen eintragen, weder am Anfang noch weiter hinten.

Wie das mit 0\d* funktionieren soll, hab ich nicht verstanden.

Meine Überlegung war ja auch ein bisschen in diese Richtung, dass ich für das 1. Zeichen [1-9] erlaube und für die weiteren Zeichen[0-9]+, aber das klappte irgendwie nicht, bzw. ich weiss nicht wie ich das zusammenbauen soll.
 
Dann zeig mal was du da genau machst: Code.
Vermutlich verwendest du nicht
Code:
.matches
, sondern suchst nach dem RegEx im String.

Und die das mit der führenden 0 funktionieren soll:
Du kannst entweder die richtigen eingaben mit
Code:
[1-9]{1}\d*
prüfen, oder die falschen mit
Code:
0\d*
, je nach dem wie du es haben willst.
 
Na ja, wie schon gesagt, ich mache das mit einem DocumentFilter:
Java:
import javax.swing.text.AttributeSet;
import javax.swing.text.BadLocationException;
import javax.swing.text.DocumentFilter;

/**
 * Filter für Textfelder für bestimmte Zeichenlänge und Muster
 * @param maxChars maximal zulässige Zeichenlänge
 * @param pattern Muster für Texteingabe
 */
public class DocumentSizeFilter
extends DocumentFilter {
	
	// Pattern für Buchstaben, Sonderzeichen, Leerzeichen und Bindestrich
	public static final String TEXT_PATTERN = "[ A-Za-z-\\xC0-\\xFF]+";
	
	// Pattern nur für Ziffern
	public static final String NUMBER_PATTERN = "[0-9]+";
	
	// Pattern für Ziffern ohne null am Anfang	
	public static final String NUMBER_PATTERN2 = "[1-9]{1}\d*";

	private final int maxCharacters;
	private final String pattern;
	    

	public DocumentSizeFilter( final int maxChars, final String pattern ) {
		maxCharacters = maxChars;
		this.pattern = pattern;
	}

	
	@Override
    public void replace( FilterBypass fb, int offs, int length, String str, AttributeSet a )
            throws BadLocationException {
		
        if ( str.matches( pattern ) && ( fb.getDocument().getLength() + str.length() - length ) <= maxCharacters || str.isEmpty() ) {
            super.replace( fb, offs, length, str, a );
        }
        
    }

}

Bei meinem Textfeld setze ich dann den DocumentFilter und übergebe die max. Zeichenlänge und das Pattern:
Java:
( ( AbstractDocument ) textfeld.getDocument()).setDocumentFilter( new DocumentSizeFilter( 7, DocumentSizeFilter.NUMBER_PATTERN2 ) );
 
Naja, dann mach Debug-ausgaben rein um zu gucken was da passiert. Der RegEx müsste stimmen.
Es könnte helfen fürs erste die if-Abfrage auseinander zu nehmen und die Werte zu überprüfen.
 
Bei
Code:
"[1-9]{1}\d*"
bekomme ich ja in Eclipse eine Fehlermeldung. Ist es dann richtig,
Code:
"[1-9]{1}\\d*"
zu schreiben?
 
Hmm, also mit dem Pattern
Code:
[1-9]{1}\\d*
bekomme ich mit
Code:
str.matches( pattern )
immer
Code:
false
heraus, wenn ich eine Null eingebe, sowohl am Anfang des Textfeldes, als auch an einer weiter hinteren Stelle. Die Zahlen 1-9 ergeben
Code:
true
.
 
Ich glaube, ich hab das Problem gefunden. Und zwar nimmt sich der DocumentFilter immer nur 1 Zeichen, welches in
Code:
str
ist, und überprüft das mit dem Pattern
Code:
str.matches( pattern )
. Und da ja im Pattern festgelegt wurde, dass das 1. Zeichen nur 1-9 und nicht 0 sein darf, schlägt das fehl. Es wird eben nicht der komplette (hier 7-stellige) String überprüft, sondern immer nur Zeichen für Zeichen. Aber das brauche ich ja auch mit dem DocumentFilter, weil damit ja verhindert werden soll, dass falsche Zeichen in die Textfelder eingegeben werden können. OK, Problem erkannt, doch wie finde ich eine Lösung?
 
Das liegt daran, das str an dieser Stelle immer nur das aktuell eingegebene Zeichen ist. Wenn du den offset (offs) mit einbeziehst müsste das klappen.

Edit: Warst wohl selber schneller.
 
Das liegt daran, das str an dieser Stelle immer nur das aktuell eingegebene Zeichen ist. Wenn du den offset (offs) mit einbeziehst müsste das klappen.
Danke für den Tipp. Bin da gerade am herumprobieren und weiss momentan noch nicht, wie ich den offset mit einbeziehen kann. Falls dir da was einfällt, ansonsten werde ich erstmal weiter probieren...
 
Hallo und sorry, war gestern grade dabei ne Antwort zu schreiben, als Kundschaft ins Büro kam.
Falls es noch akut ist, hier ein Codeschnippsel:

Java:
((AbstractDocument) textField.getDocument())
				.setDocumentFilter(new DocumentFilter() {

					@Override
					public void replace(FilterBypass fb, int offset,
							int length, String text, AttributeSet attrs)
							throws BadLocationException {
						if (text.matches("[1-9]{1}\\d*")) {
							super.replace(fb, offset, length, text, attrs);
						}
						if(offset > 0){
							String str = textField.getText();
							str = str + text;
							if (str.matches("[1-9]{1}\\d*")) {
								super.replace(fb, offset, length, text, attrs);
							}
						}
					}
				});
 
Hallo, danke für die Hilfe. Leider funktionierte dein Tipp nicht so ganz richtig. Aber der Hinweis auf das Offset war genau richtig. Es wurde zwar verhindert, dass als erstes eine Null eingegeben werden durfte, aber dafür wurden ab der 2. Stelle die eingegebenen Ziffern doppelt ausgegeben und die Null wurde verhindert.

Ich hab's jetzt mal ein bisschen umgeschrieben. Ist auch in einer eigenen Klasse, da ich das in der Anwendung an mehreren Stellen brauche:
Java:
import javax.swing.text.AttributeSet;
import javax.swing.text.BadLocationException;
import javax.swing.text.DocumentFilter;

public class MatrikelFilter
extends DocumentFilter{
	
	private final int maxCharacters;
	    

	public MatrikelFilter( final int maxChars ) {
		
		maxCharacters = maxChars;
		
	}

	
	@Override
    public void replace( FilterBypass fb, int offs, int length, String text, AttributeSet a )
            throws BadLocationException {


		if( offs==0) {
            if (text.matches("[1-9]{1}\\d*")) {
                super.replace(fb, offs, length, text, a);
            }			
		}
		
		else if ( text.matches( "\\d*" ) && ( fb.getDocument().getLength() + text.length() - length ) <= maxCharacters || text.isEmpty() ) {
            super.replace( fb, offs, length, text, a );
        }
        
    }

}
Muss ich mal schauen, ob sich das noch optimieren lässt, da ja z.B. das super.replace zweimal identisch aufgerufen wird...

Aufgerufen wird das auf meinem Panel mit dem Formular so:
Java:
( ( AbstractDocument ) tfMatrikelnummer.getDocument()).setDocumentFilter( new MatrikelFilter( 7 ) );

Damit übergebe ich die maximale Zeichenanzahl, die für dieses Textfeld zugelassen sein soll.

Eigentlich wollte ich mir ja einen DocumentFilter erstellen, der für verschiedene Anforderungen genommen werden kann, und als Parameter die max. Zeichenanzahl und ein Pattern übergeben bekommt. Na ja, noch ein bisschen grübeln und umbauen, dann schaff ich das bestimmt auch noch.

Danke nochmal für die Hilfe...
Camino
 

Zurück
Oben