2012-04-04 3 views
0

Ich habe die folgende Methode:RegExpr Verwirrung mit negierten Zeichenklassen?

protected BigDecimal stringToBigDecimal(String value) throws ParseException 
{ 
    if (Pattern.matches("[\\d,.]+", value)) 
    { 
     Number n = NumberFormat.getInstance().parse(value); 

     return new BigDecimal(n.doubleValue()); 
    } 
    else 
    { 
     throw new ParseException("Invalid String", -1); 
    } 
} 

Dieser Wert zeigt eine Ausnahme auslöst (wie erwartet), so dass dieser RegExpr funktioniert:

String wrongAmount = "1,U35,345.43"; 

Aber wenn ich versuche dies:

protected BigDecimal stringToBigDecimal(String value) throws ParseException 
{ 
    if (Pattern.matches("[\\D&&[^.,]]+", value)) 
    { 
     throw new ParseException("Invalid String", -1); 
    } 

    Number n = NumberFormat.getInstance().parse(value); 

    return new BigDecimal(n.doubleValue()); 
} 

Keine Ausnahme wird geworfen, aber warum? Zuerst dachte ich, dass es ein logisches Problem mit der „Ausnahme“ Ausdruck so dass ich diesen Wert mit diesem Muster versucht:

String wrongAmount = "1U3534543"; 

protected BigDecimal stringToBigDecimal(String value) throws ParseException 
{ 
    if (Pattern.matches("[\\D]+", value)) 
    { 
     throw new ParseException("Invalid String", -1); 
    } 

    Number n = NumberFormat.getInstance().parse(value); 

    return new BigDecimal(n.doubleValue()); 
} 

... aber das stimmt nicht überein? Was habe ich falsch verstanden auf dem "non-digit expression" \\D.. Der Wert enthält ein "U", also warum passt es nicht?

Antwort

0

Sie negieren nicht richtig Ausdrücke.

Im ersten Beispiel sagen Sie "Wenn meine Eingabe nur mit Ziffern, Kommas und Punkten übereinstimmt", dann ist es in Ordnung.

In Ihrem zweiten Beispiel (und ich bin nicht sicher, dass es das tut, was Sie meinten, aber das ist eine andere Geschichte), wollten Sie sagen "wenn die Eingabe nur Nicht-Ziffern, Nicht-Kommas, Nicht-Punkte-Zeichen entspricht", aber Ihre Eingabe enthält Ziffern, so dass die Übereinstimmung nicht funktioniert.

In Ihrem letzten Beispiel, die gleiche Sache, Sie sagen „wenn der Eingang nur nicht-stellige Zeichen übereinstimmt“, aber wieder haben Sie Ziffern in Ihrem Eingang

+0

Ah, du hast Recht. Logische Verwirrung :) – Bevor

+0

Das zweite Beispiel sagt das nicht wirklich. Lies meine Antwort. – NullUserException

+0

@NullUserException und lesen Sie, was ich in meiner Klammer sage! –

2

wir jedes Ihrer Muster sezieren:

Pattern.matches("[\\d,.]+", value) 

Spiel eine beliebige Zeichenfolge, die aus einer oder mehreren Ziffern, Kommas und Punkte besteht.

Pattern.matches("[\\D&&[^.,]]+", value) 

Sie können Zeichenklassen nicht kombinieren, wie Sie es hier tun. Was Sie wirklich mit [\\D&&[^.,]] sagen, ist "passen Sie alle nicht-Ziffer Zeichen, außer der Punkt und Komma." Der richtige Weg, um diesen regex zu schreiben wäre:

[^\\d,.] # match anything but digits, comma and dot 

Last but not least:

Pattern.matches("[\\D]+", value) 

Das bedeutet: "Match eine nicht leere Zeichenfolge völlig von nicht-nummerische Zeichen besteht"

Pattern.matches() versucht, die gesamte Zeichenfolge gegen einen regulären Ausdruck übereinzustimmen. Sie möchten stattdessen Matcher.find() verwenden, wenn Sie nur einen Teil der Zeichenfolge abgleichen möchten.

Schließlich missverstehen Sie, wie die + funktioniert. + ist ein Quantifizierer, der "1 oder mehr" bedeutet. Es tut nicht, was du denkst, dass es tut.

+0

Aber matches() passen würde, wenn ich auf das Pluszeichen nach der Zeichenklasse setzen, wie ich. Und Javadoc sagt, dass Sie Zeichenklassen kombinieren können: docs.oracle.com/javase/6/docs/api/java/util/regex/Pattern.html "[a-z && [^ bc]] a bis z, mit Ausnahme von b und c: [ad-z] (Subtraktion) " – Bevor

+0

@Bevor Lesen Sie meinen aktualisierten Beitrag. Sie liegen falsch in beiden Teilen. – NullUserException

+0

Ok, Matcher.find() würde wahrscheinlich auch eine Lösung sein. – Bevor

0

Ich glaube, Sie dies wünschen:

if (value.matches(".*[^\\d.,].*")) { 
    throw new ParseException("Invalid String", -1); 
} 

Beachten Sie die hinzugefügte ".*" an der Vorder- und Rückseite, weil String.matches()true nur zurückgibt, wenn das Muster dem gesamten Eingang entspricht.

Jedoch habe ich es zu einem negativen Spiel ändern würde, weil es einfacher ist, zu lesen:

if (!value.matches("[\\d.,]+")) { 
    throw new ParseException("Invalid String", -1); 
}