我有这段代码,我将一个Pattern键和一个String标记插入一个hashmap:
while( (word = reservedWordsRead.readLine()) != null ) {
String[] k = word.split(" ");
infoList.put(Pattern.compile("^("+k[0]+")"), //lexeme
k[1]); //token
}
它从一个如下文件中读取:
) rparen
( lparen
但是括号无法识别,因此我将文件修改为如下所示:
\\) rparen
\\( lparen
和这样的代码:
while( (word = reservedWordsRead.readLine()) != null ) {
String[] k = word.split(" ");
infoList.put(Pattern.compile("^("+Pattern.quote(k[0])+")"), //lexeme
k[1]); //token
}
但我没有得到正确的输出。它与任何东西都不匹配。此外,rparen和lparen被插入到hashmap中,因为我能够使用我的tokenizer()方法打印以下内容:
pattern: ^(\Q\\)\E), token: rparen
pattern: ^(\Q\\(\E), token: lparen
这是我的标记器方法:
public void tokenize(String str) {
String s = str.trim();
tokenList.clear();
while (!s.equals("")) {
boolean match = false;
for ( Entry<Pattern,String> thing: infoList.entrySet() ) {
System.out.println("pattern: "+thing.getKey().toString()+", token: "+thing.getValue());
Matcher m = thing.getKey().matcher(s);
if (m.find()) {
match = true;
String tok = m.group().trim();
s = m.replaceFirst("").trim();
tokenList.put(tok,thing.getValue());
break;
}
} if (!match)
throw new ParserException("Unexpected character in input: "+s);
}
}
我不确定我做错了什么..非常感谢你的帮助:)。
答案 0 :(得分:1)
如果您想匹配完整的字符串,则应使用Pattern.quote()
。
你遇到的问题是你试图引用传递的字符串和转义括号,基本上是双转义(让人联想到HTML中的&amp;
)。虽然可以将所有特殊转义字符放在输入文件中,但为什么要这么麻烦?让Pattern
为您完成工作。
这是一个测试,我们尝试使用几个不同的输入并尝试将它们变成Pattern
,就像你一样。
import java.util.regex.Pattern;
import java.util.regex.PatternSyntaxException;
public class RegexTest
{
private static final String[] TESTS = {"a","(","\\(","\\\\(","[letters]"};
public static void main(String[] args) {
for(String test : TESTS) {
examineRegex(test);
System.out.println();
}
}
public static void examineRegex(String match) {
System.out.println("Testing "+match);
String template = "^(%s)";
String regex = String.format(template, match);
examinePattern(match, regex);
String quotedRegex = String.format(template, Pattern.quote(match));
examinePattern(match, quotedRegex);
}
public static void examinePattern(String match, String regex) {
try {
Pattern pattern = Pattern.compile(regex);
System.out.println(" Compiled: "+pattern);
System.out.println(" Match?: "+pattern.matcher(match).matches());
} catch (PatternSyntaxException e) {
System.out.println(" Failed to compile: "+e.getMessage()
.substring(0, e.getMessage().indexOf('\n')));
}
}
}
此程序的输出如下(注释内联):
Testing a
Compiled: ^(a)
Match?: true
Compiled: ^(\Qa\E)
Match?: true
对于“普通”字符串的简单情况,原始方法和使用Pattern.quote()
都有效。到目前为止一切都很好。
Testing (
Failed to compile: Unclosed group near index 4
Compiled: ^(\Q(\E)
Match?: true
但是如果我们传入一个构造,例如(
,我们会收到一个错误,除非我们引用它。
Testing \(
Compiled: ^(\()
Match?: false
Compiled: ^(\Q\(\E)
Match?: true
如果我们传入一个转义构造,原始模式会成功编译,但它与输入字符串不匹配。那不是世界末日 - 它会匹配(
- 但这是违反直觉的;它破坏了传入的东西是我们匹配的期望。
Testing \\(
Failed to compile: Unclosed group near index 6
Compiled: ^(\Q\\(\E)
Match?: true
现在我们双重逃避模式,就像试图将输入视为Java字符串一样。这表明在尝试确定需要转移多少时可能会产生混淆。
Testing [letters]
Compiled: ^([letters])
Match?: false
Compiled: ^(\Q[letters]\E)
Match?: true
最后,假设我们想匹配一个也是实际正则表达式的字符串?它将成功编译,因此无法提醒我们该问题,但将无法匹配预期的字符串。
如您所见,Pattern.quote()
每次都有效,并且无需将正则表达式的实现细节放入数据文件中。这样,您可以隐藏文本文件中匹配实际发生方式的实现细节,这种划分会产生强大的代码。
当然,如果您在文件中想要的是正则表达式列表,您显然不想使用Pattern.quote()
,而是需要明确表达它期望用户输入需要是有效的Java正则表达式,并且可能会产生可怜的模式。
答案 1 :(得分:0)
\) rparen
和java字符串"...\\)..."
中的反斜杠必须加倍以表示反斜杠。然后不需要quote
,它也会更加间接。