【问题标题】:How do you use the Java word boundary with apostrophes?如何使用带有撇号的 Java 单词边界?
【发布时间】:2014-02-11 05:58:13
【问题描述】:

我正在尝试删除列表中所有出现的单词,但是当单词中有撇号时我遇到了麻烦。

String phrase="bob has a bike and bob's bike is red";
String word="bob";
phrase=phrase.replaceAll("\\b"+word+"\\b","");
System.out.println(phrase);

输出:
has a bike and 's bike is red

我想要的是
has a bike and bob's bike is red

我对正则表达式的了解有限,所以我猜有一个解决方案,但我现在还不足以创建正则表达式来处理撇号。此外,我希望它与破折号一起使用,因此短语 the new mail is e-mail 只会替换第一次出现的邮件。

【问题讨论】:

  • 我不会在 Java 模式中使用 \b:它是超级坏的。有一种方法可以正确表达,但无论如何这不太可能是您想要的。
  • 这是我提取单个单词的酷刑测试:James 问:“这是 Renée 和 Noël 的曾祖父母 1970 年代的避暑别墅,不是吗? ?”没有得到回答,他摇了摇头——然后走开了。 作为一个 Java 字符串,你可以写成 "James asked, \u201C\u2019Tis Ren\u00E9e\u2019s and Noe\u0308l\u2019s great\u2010grandparents\u2019 1970's-ish summer\u2010house, t'isn\u2019t it?\u201D \u00A0 Receiving no answer, he shook his head--and walked away."。祝你好运!
  • @tchrist 我正在摇头走开,哈哈。对于我正在做的事情,我不需要担心所有这些可能发生的事情。但这看起来确实是一个有趣的挑战。

标签: java regex


【解决方案1】:

这完全取决于您对“单词”的理解。或许你最好把你所理解的定义为单词分隔符:例如,空格、逗号....并写成

phrase=phrase.replaceAll("([ \\s,.;])" + Pattern.quote(word)+ "([ \\s,.;])","$1$2");

但是您必须另外检查字符串的开头和结尾是否出现 例如:

  String phrase="bob has a bike bob, bob and boba bob's bike is red and \"bob\" stuff.";
  String word="bob";
  phrase=phrase.replaceAll("([\\s,.;])" + Pattern.quote(word) + "([\\s,.;])","$1$2");
  System.out.println(phrase);

打印这个

bob has a bike ,  and boba bob's bike is red and "bob" stuff.

更新:如果你坚持使用\b,考虑到“单词边界”理解Unicode,你也可以做这个肮脏的把戏:用一些你确定会的Unicode字母替换所有出现的'不会出现在您的文本中,然后进行反向替换。示例:

  String phrase="bob has a bike bob, bob and boba bob's bike is red and \"bob\" stuff.";
  String word="bob";
  phrase= phrase.replace("'","ñ").replace('"','ö');
  phrase=phrase.replaceAll("\\b" + Pattern.quote(word) + "\\b","");
  phrase= phrase.replace('ö','"').replace("ñ","'");
  System.out.println(phrase);

更新:总结下面的一些 cmets:人们会期望 \w\b 对于“单词字符”具有相同的概念,就像几乎所有正则表达式方言一样。好吧,Java 没有:\w 考虑 ASCII,\b 考虑 Unicode。这是一个丑陋的不一致,我同意。

更新 2:由于 Java 7(如 cmets 中所指出的)UNICODE_CHARACTER_CLASS 标志允许指定一致的仅 Unicode 行为,请参阅例如 here

【讨论】:

  • @leonbloy 在程序的早期,我已经去掉了除'- 之外的所有标点符号。我喜欢\b,因为它在没有空格的字符串的开头和结尾工作。
  • 嗯,'\b' 确实不错,但我不认为 Java 允许您重新定义“word”类。另一个肮脏的技巧是将您的' 替换为您确定不会出现在短语中的某些单词,应用原始正则表达式,然后进行反向替换。很脏,但有时很实用。
  • 我曾短暂地考虑过用一个东西来代替'-,但即使它非常hackish,我认为这是最快最简单的解决方案。感谢您的帮助。
  • \b 应该(?:(?<=\w)(?!\w)|(?<!\w)(?=\w)) 相同——但 Java 轻率地打破了这一点。同样,\w应该[\pL\pM\p{Nd}\p{Nl}\p{Pc}[\p{InEnclosedAlphanumerics}&&\p{So}]。将一个换成另一个,以便 Java 可以理解它产生 \b 实际上 supposed(?:(?<=\[\pL\pM\p{Nd}\p{Nl}\p{Pc}[\p{InEnclosedAlphanumerics}ww\p{So}])(?!\[\pL\pM\p{Nd}\p{Nl}\p{Pc}[\p{InEnclosedAlphanumerics}&&\p{So}])|(?<!\[\pL\pM\p{Nd}\p{Nl}\p{Pc}[\p{InEnclosedAlphanumerics}&&\p{So}])(?=\[\pL\pM\p{Nd}\p{Nl}\p{Pc}[\p{InEnclosedAlphanumerics}&&\p{So}]))
  • @tchrist:你能指出那些声明\b 不是它应该是的文档吗?我发现的网站(answers.oreilly.com/topic/…regular-expressions.info/wordboundaries.html)表明至少 \b 可以正常工作。
【解决方案2】:
\b\S*(bob|mail)\S*\b

小心误报,这可能会超出您的预期。如果您需要不超过 2 个字符的“前缀”或“后缀”(例如 "'s""e-"),请使用 \S{0,2} 而不是 \S*

正则表达式说:

\b           # a word boundary
\S*          # any number of non-spaces
(            # match group 1 (to enable a choice) 
  bob|mail   #   "bob" or "mail"
)            # end match group 1
\S*          # any number of non-spaces
\b           # a word boundary

所以,在 Java 中:

phrase = phrase.replaceAll("\\b\\S*(bob|mail)\\S*\\b", "");

小心

之类的东西
phrase = phrase.replaceAll("\\b" + word + "\\b", "");

应该是这样的

phrase = phrase.replaceAll("\\b" + Pattern.quote(word) + "\\b", "");

因为每当word 包含正则表达式元字符时,除非您正确地使用escape the string beforehand using Pattern.quote(),否则您的正则表达式将会中断。

【讨论】:

  • 不,这是误导。您不能将单词边界与非 ASCIISpace 之类的东西混合在一起。这是因为\b\S+bob 模式无法匹配 字符串,例如"==bob"。此外,\b 在 Java 中完全被破坏了,因为字符串 "élève" 无法完全通过 Pattern.matches() 与模式 \b\w+\b 匹配,但实际上甚至在使用 Pattern.find() 的字符串中的任何点都没有匹配!
  • @tchrist:像“==bob”这样的东西不是问题规范的一部分,所以我没有费心去预测它们。不过,关于\b 被破坏的好点。但是,我暂时保持答案不变,因为它适用于 OP 给出的案例。除非问题变得更具体,否则我将无所事事,也无法真正改进我的答案。
  • @Tomalak:同意。有这么多问题的一个问题是,他们实际上并没有完全指出问题,以便找到适当的解决方案。另一个是当他们认为他们的解决方案首先是解决问题的方法。
  • @tchrist:一些消息来源表明 \b 实际上在 Java 中启用了 Unicode:answers.oreilly.com/topic/…,因此一切正常。
  • @Tomalak 我在另一篇文章中提到我删除了除'- 之外的所有非字母字符。我应该在问题中提到这一点。我对您的回答有一半理解,但它似乎与其中包含 bob 的任何内容相匹配,然后替换了整个单词。如果它是 bob 而不是 bob 或 hi-bob,我希望它只替换 bob。
猜你喜欢
  • 2020-06-03
  • 2016-02-17
  • 1970-01-01
  • 1970-01-01
  • 2016-05-08
  • 1970-01-01
  • 2014-07-07
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多