java—从文件中读取字符串并将其转换为文本正则表达式

java—从文件中读取字符串并将其转换为文本正则表达式,java,regex,Java,Regex,我有一段代码,其中我向hashmap插入了一个模式键和一个字符串标记: while( (word = reservedWordsRead.readLine()) != null ) { String[] k = word.split(" "); infoList.put(Pattern.compile("^("+k[0]+")"), //lexeme k[1]); //token } 它读取的文件如下所示: ) rparen (

我有一段代码,其中我向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
\\) 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
\\) 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);
    }
}
public void标记化(String str){
字符串s=str.trim();
tokenList.clear();
而(!s.equals(“”){
布尔匹配=假;
for(条目内容:infoList.entrySet()){
println(“模式:+thing.getKey().toString()+”,标记:+thing.getValue());
Matcher m=thing.getKey().Matcher;
if(m.find()){
匹配=真;
字符串tok=m.group().trim();
s=m.replaceFirst(“”.trim();
tokenList.put(tok,thing.getValue());
打破
}
}如果(!匹配)
抛出新的ParserException(“输入中的意外字符:“+s”);
}
}

我不确定我做错了什么。。非常感谢您的帮助:)

\)rparen
在文件中就像在java字符串中一样
“…\)…”
反斜杠必须加倍以表示反斜杠。这样就不需要
quote
,它也可以做得更具体一些。

如果要匹配精确的字符串,应该使用
Pattern.quote()

遇到的问题是,您试图引用传递的字符串并转义括号,本质上是双重转义(让人想起HTML中的
&;amp;
)。虽然可以将所有特殊转义字符放入输入文件中,但为什么还要麻烦呢?让
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')));
        }
    }
}
该程序的输出如下(注释内联):

对于“普通”字符串的简单情况,原始方法和using
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正则表达式,并且提供糟糕的模式可能会导致潜在的混乱结果。

您能否向这位困惑不解的读者解释一下您所说的“它也做得更间接一点”是什么意思你可以自己做一个
System.out.println(Pattern.quote(“”);
如果我做对了,它会给出
\Q(\E
。哇,这非常有用。我也不想在我的文件中列出正则表达式。谢谢。。