Das ist meine Dienstprogramm Methode zu überprüfen, ob ein replacement string gültig ist:überprüfen Sie, ob Ersatzzeichenfolge gültig ist
public static boolean isValidReplacementString(String regex, String replacement) {
try {
"".replaceFirst(regex, replacement);
return true;
} catch (IllegalArgumentException | NullPointerException e) {
return false;
}
}
Ich mag würde dies zu überprüfen, bevor der realen Ersatz Ausführung, da die Quellzeichenfolge bekommen (n) teuer (I/O).
Ich finde diese Lösung ziemlich hacky. Gibt es bereits eine Methode in der Standardbibliothek, die ich vermisse?
Edit: As pointed out by sln, bedeutet dies nicht auch funktionieren, wenn keine Übereinstimmung gefunden wird.
Edit: Following shmosel's answer, kam ich mit dieser "Lösung" up:
private static boolean isLower(char c) {
return c >= 'a' && c <= 'z';
}
private static boolean isUpper(char c) {
return c >= 'A' && c <= 'Z';
}
private static boolean isDigit(char c) {
return isDigit(c - '0');
}
private static boolean isDigit(int c) {
return c >= 0 && c <= 9;
}
@SuppressWarnings("unchecked")
public static void checkRegexAndReplacement(String regex, String replacement) {
Pattern parentPattern = Pattern.compile(regex);
Map<String, Integer> namedGroups;
int capturingGroupCount;
try {
Field namedGroupsField = Pattern.class.getDeclaredField("namedGroups");
namedGroupsField.setAccessible(true);
namedGroups = (Map<String, Integer>) namedGroupsField.get(parentPattern);
Field capturingGroupCountField = Pattern.class.getDeclaredField("capturingGroupCount");
capturingGroupCountField.setAccessible(true);
capturingGroupCount = capturingGroupCountField.getInt(parentPattern);
} catch (NoSuchFieldException | IllegalAccessException e) {
throw new RuntimeException("That's what you get for using reflection!", e);
}
int groupCount = capturingGroupCount - 1;
// Process substitution string to replace group references with groups
int cursor = 0;
while (cursor < replacement.length()) {
char nextChar = replacement.charAt(cursor);
if (nextChar == '\\') {
cursor++;
if (cursor == replacement.length())
throw new IllegalArgumentException(
"character to be escaped is missing");
nextChar = replacement.charAt(cursor);
cursor++;
} else if (nextChar == '$') {
// Skip past $
cursor++;
// Throw IAE if this "$" is the last character in replacement
if (cursor == replacement.length())
throw new IllegalArgumentException(
"Illegal group reference: group index is missing");
nextChar = replacement.charAt(cursor);
int refNum = -1;
if (nextChar == '{') {
cursor++;
StringBuilder gsb = new StringBuilder();
while (cursor < replacement.length()) {
nextChar = replacement.charAt(cursor);
if (isLower(nextChar) ||
isUpper(nextChar) ||
isDigit(nextChar)) {
gsb.append(nextChar);
cursor++;
} else {
break;
}
}
if (gsb.length() == 0)
throw new IllegalArgumentException(
"named capturing group has 0 length name");
if (nextChar != '}')
throw new IllegalArgumentException(
"named capturing group is missing trailing '}'");
String gname = gsb.toString();
if (isDigit(gname.charAt(0)))
throw new IllegalArgumentException(
"capturing group name {" + gname +
"} starts with digit character");
if (namedGroups == null || !namedGroups.containsKey(gname))
throw new IllegalArgumentException(
"No group with name {" + gname + "}");
refNum = namedGroups.get(gname);
cursor++;
} else {
// The first number is always a group
refNum = (int)nextChar - '0';
if (!isDigit(refNum))
throw new IllegalArgumentException(
"Illegal group reference");
cursor++;
// Capture the largest legal group string
boolean done = false;
while (!done) {
if (cursor >= replacement.length()) {
break;
}
int nextDigit = replacement.charAt(cursor) - '0';
if (!isDigit(nextDigit)) { // not a number
break;
}
int newRefNum = (refNum * 10) + nextDigit;
if (groupCount < newRefNum) {
done = true;
} else {
refNum = newRefNum;
cursor++;
}
}
}
if (refNum < 0 || refNum > groupCount) {
throw new IndexOutOfBoundsException("No group " + refNum);
}
} else {
cursor++;
}
}
}
Wenn diese Methode wirft, entweder die Regex oder die Ersatzzeichenfolge ist ungültig.
Dies ist noch strenger als replaceAll
oder replaceFirst
, da diese Methoden appendReplacement
nicht aufrufen werden, wenn keine Übereinstimmung gefunden wird, daher ungültige Gruppenreferenzen "fehlen".
Ich bin nicht sicher, ob die Engine die Ersetzungszeichenfolge prüfen wird, wenn es keine Übereinstimmung gibt, könnte ich falsch liegen. Einige Fehler zum Zeitpunkt des Ersetzens könnten jedoch ungültig sein. Die Rückreferenz der Erfassungsgruppe ist in der Regex nicht definiert. – sln
Verwenden Sie die Methode "apache StringUtils.isNotNull", um vor dem Ersetzen auf Null zu prüfen. – amitmah
@sln Sie haben Recht. 'isValidReplacementString (" test "," $ ")' gibt 'true' zurück, weil keine Übereinstimmung gefunden wurde. Also meine Methode funktioniert nicht einmal richtig. – xehpuk