除了“&”或“'”模式之外,删除所有非单词字符

9

我想清除一个字符串中除了&之外的所有非单词字符,例如模式可能是&[\w]+;

例如:

abc; => abc
abc & => abc &
abc& => abc  

如果我使用string.replaceAll("\W",""),它会从第二个示例中同时移除;'&',而我并不希望这样。在此问题中使用否定预查是否可以给出一个快速解决正则表达式模式的方法?
3个回答

2

我不确定你能够使用简单的String.replaceAll方法来实现这个功能。你应该使用PatternMatcher来循环匹配,相当于手动查找和替换。以下代码应该可以解决问题。

public String replaceString(String origString) {
    Pattern pattern = Pattern.compile("&(\w+);|[^\w]");
    Matcher matcher = pattern.matcher(origString);
    StringBuffer sb = new StringBuffer();
    while (matcher.find()) {
        if (matcher.group().startsWith("&") && !matcher.group(1).equals("amp")) {
            matcher.appendReplacement(sb, matcher.group());
        } else {
            matcher.appendReplacement(sb, "");
        }
    }
    matcher.appendTail(sb);
    return sb.toString();
}

2
首先,我很喜欢这个问题。现在,你想要的不能通过单个replaceAll实现,因为我们需要一个具有可变长度的negative look-behind,而这是不允许的。如果它被允许,那么就不会那么难了。
无论如何,在这里单个replaceAll不是一个选择,你可以使用一个小技巧。比如先用一些字符序列替换你entity reference的最后一个分号,你要确信这个字符序列在其余字符串中不存在,比如XXX或其他任何字符。我知道这不正确,但你肯定无法解决它。
所以,这里是你可以尝试的方法:
String str = "a;b&c &";

str  = str.replaceAll("(&\\w+);", "$1XXX")
          .replaceAll("&(?!\\w+?XXX)|[^\\w&]", "")
          .replaceAll("(&\\w+)XXX", "$1;");

System.out.println(str);

说明:

  • 第一个replaceAll将像&这样的模式替换为&ampXXX,或者任何最后一个;替换的序列。
  • 第二个replaceAll将替换任何没有跟随\\w+XXX或任何非单词、非&字符的&。这将替换所有不属于&类型模式的&。此外,还会替换任何其他非单词字符。
  • 第三个replaceAll重新将XXX替换为;,以从&ampXXX创建回来&

为了更容易理解,您可以使用PatternMatcher类,每当替换标准复杂时,我都更喜欢使用它们。

String str = "a;b&c &";

Pattern pattern = Pattern.compile("&\\w+;|[^\\w]");
Matcher matcher = pattern.matcher(str);

StringBuilder sb = new StringBuilder();

while (matcher.find()) {
    String match = matcher.group();
    if (!match.matches("&\\w+;")) {
        matcher.appendReplacement(sb, "");
    } else {
        matcher.appendReplacement(sb, match);
    }
}
matcher.appendTail(sb);
System.out.println(sb.toString());

这个代码与@Eric的代码类似,但是是对其进行了概括。那个代码只能在&上工作,当然,如果它被改进以消除其中抛出的NullPointerException,那么它也可以运行。


不错的答案,虽然一开始我还想要一个更简洁的解决方案。 - dreamcrash
@dreamcrash。如果 Java Regex 允许变长的 look-behind,那么这段代码可以更加紧凑。在这种情况下,替换操作就可以像这样简单明了:str.replaceAll("(?<!&\\w+);|&(?!\\w+-)|[^\\w;&]", ""); - Rohit Jain
据我所知,一些正则表达式引擎确实允许可变长度的后顾断言,但我不太记得它们是哪些。@dreamcrash - Rohit Jain
谢谢回复,我并不是在批评这个解决方案本身。只是每次看到正则表达式回答问题,就会感觉它很简单、优雅。真的需要学习如何使用正则表达式 :D - dreamcrash

0
我建议您使用类似于这样的负向先行断言:
string.replace(/&(?!\w+;)/ig, '');

这个代码用于替换所有不跟随以分号结尾的单词字符的 & 符号。

编辑(Java):

string.replaceAll("/&(?!\w+;)/i", '');

哈哈,我确实读过“JavaScript”……所以我的编辑应该在Java中起作用。 - crackmigg

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接