【问题标题】:Issue with below snippet on boundary matchers regex (\b)边界匹配器正则表达式 (\b) 上的以下片段问题
【发布时间】:2017-05-08 07:14:13
【问题描述】:

我的意见:

 1. end 
 2. end of the day or end of the week 
 3. endline
 4. something 
 5. "something" end

基于上述讨论,如果我尝试使用这个 sn-p 替换单个字符串,它会成功从该行中删除相应的单词

public class DeleteTest {

    public static void main(String[] args) {

        // TODO Auto-generated method stub
        try {
        File file = new File("C:/Java samples/myfile.txt");
        File temp = File.createTempFile("myfile1", ".txt", file.getParentFile());
        String delete="end";
        BufferedReader reader = new BufferedReader(new InputStreamReader(new FileInputStream(file)));
        PrintWriter writer = new PrintWriter(new OutputStreamWriter(new FileOutputStream(temp)));

        for (String line; (line = reader.readLine()) != null;) {
            line = line.replaceAll("\\b"+delete+"\\b", "");
       writer.println(line);
        }
        reader.close();
        writer.close();
        }
        catch (Exception e) {
            System.out.println("Something went Wrong");
        }
    }
}

我的输出如果我使用上面的 sn-p:(也是我的预期输出)

 1.  
 2. of the day or of the week
 3. endline
 4. something
 5. "something"

但是当我包含更多要删除的单词时,并且为此我使用 Set 时,我使用以下代码 sn-p:

public static void main(String[] args) {

    // TODO Auto-generated method stub
    try {

    File file = new File("C:/Java samples/myfile.txt");
    File temp = File.createTempFile("myfile1", ".txt", file.getParentFile());
    BufferedReader reader = new BufferedReader(new InputStreamReader(new FileInputStream(file)));
    PrintWriter writer = new PrintWriter(new OutputStreamWriter(new FileOutputStream(temp)));

        Set<String> toDelete = new HashSet<>();
        toDelete.add("end");
        toDelete.add("something");

    for (String line; (line = reader.readLine()) != null;) {
        line = line.replaceAll("\\b"+toDelete+"\\b", "");
    writer.println(line);
    }
    reader.close();
    writer.close();
    }
    catch (Exception e) {
        System.out.println("Something went Wrong");
    }
}

我的输出为:(它只是删除了空间)

 1. end
 2. endofthedayorendoftheweek
 3. endline
 4. something
 5. "something" end 

你们能帮我解决这个问题吗?

Click here to follow the thread

【问题讨论】:

  • 您使用的是 Java 8 还是 Java 7?
  • 我使用的是 Java 8

标签: java regex set


【解决方案1】:

您需要在集合之外创建一个alternation group

String.join("|", toDelete)

并用作

line = line.replaceAll("\\b(?:"+String.join("|", toDelete)+")\\b", "");

图案看起来像

\b(?:end|something)\b

请参阅regex demo。这里,(?:...) 是一个 非捕获 组,用于在不为捕获创建内存缓冲区的情况下分组多个备选方案(您不需要它,因为您删除了匹配)。

或者,更好的是,在进入循环之前编译正则表达式:

Pattern pat = Pattern.compile("\\b(?:" + String.join("|", toDelete) + ")\\b");
...
    line = pat.matcher(line).replaceAll("");

更新

要允许匹配可能包含特殊字符的整个“单词”,您需要 Pattern.quote 这些单词以转义这些特殊字符,然后您需要使用明确的单词边界 (?&lt;!\w) 而不是最初的 \b确保之前没有单词 char 和 (?!\w) 否定前瞻而不是最后的 \b 以确保匹配后没有单词 char。

在 Java 8 中,您可以使用以下代码:

Set<String> nToDel = new HashSet<>();
nToDel = toDelete.stream()
    .map(Pattern::quote)
    .collect(Collectors.toCollection(HashSet::new));
String pattern = "(?<!\\w)(?:" + String.join("|", nToDel) + ")(?!\\w)";

正则表达式看起来像(?&lt;!\w)(?:\Q+end\E|\Qsomething-\E)(?!\w)。注意\Q\E 之间的符号被解析为文字符号

【讨论】:

  • 感谢维克托。你能建议一种在正则表达式模式中添加诸如括号和特殊字符之类的方法吗?
  • @venk:你的意思是你的toDelete项目中会有非单词(非字母/数字/_)?那么您的基于单词边界的方法可能无法找到匹配项(如果这些非单词字符出现在开头/结尾处,如\b(?:+end|something-)\b 中)。您需要在所有项目上运行Pattern.quote,然后使用(?&lt;!\w)(?!\w) 而不是\bs。
  • @venk:查看更新后的答案。如果它适合您,请考虑接受。
  • 感谢您的解决方案。按预期工作。 :)
【解决方案2】:

问题在于您没有创建正确的正则表达式来替换集合中的单词。

"\\b"+toDelete+"\\b" 将生成这个字符串\b[end, something]\b,这不是您需要的。

要解决这个问题,您可以执行以下操作:

for(String del : toDelete){
    line = line.replaceAll("\\b"+del+"\\b", "");
}

它的作用是遍历集合,从每个单词中生成一个正则表达式,然后从line 字符串中删除该单词。

另一种方法是从集合中的所有单词生成一个正则表达式。

例如:

String regex = "";
for(String word : toDelete){
   regex+=(regex.isEmpty() ? "" : "|") + "(\\b"+word+"\\b)";
}
....
line = line.replace(regex, "");

这应该产生一个看起来像这样的正则表达式:(\bend\b)|(\bsomething\b)

【讨论】:

  • 谢谢提图斯。您能建议一种在正则表达式中添加诸如括号和特殊字符之类的内容的方法吗?
  • @venk 您需要使用 `` 转义这些字符。您可以找到有关该HERE 的更多详细信息
猜你喜欢
  • 2014-06-20
  • 2015-11-16
  • 2022-07-06
  • 1970-01-01
  • 1970-01-01
  • 2011-03-08
  • 2012-04-21
  • 1970-01-01
  • 2011-07-17
相关资源
最近更新 更多