替换为这种模式并不像我期望的那样,有什么问题?

时间:2016-04-22 09:20:27

标签: java regex pattern-matching replaceall

我需要帮助从这句话中提取一些单词:

String keywords = "I like to find something vicous in somewhere bla bla bla.\r\n" + 
            "https://address.suffix.com/level/somelongurlstuff";

我的匹配代码看起来有点像这样:

    keywords = keywords.toLowerCase();
    regex = "(I like to find )(.*)( in )(.*)(\\.){1}(.*)";
    regex = regex.toLowerCase();
    keywords = keywords.replaceAll(regex, "$4 $2"); //"$4 $2");

我想提取find in 之间以及 in 和第一个点之间的字词。然而,由于网址有多个点,一些奇怪的东西开始发生,我得到我需要的加上url机智点替换为空的空格。我希望网址消失,因为在我的情况下,它应该与(.*)匹配,而我在(\\.){1}之后只需要一个点,所以我想知道那里出了什么问题?有什么想法吗?

通过添加(?s)或删除行上的所有新行字符,然后在正则表达式上进行匹配会给出类似于:somewhere bla bla bla address suffix something vicious的内容,因此网址的问题仍然存在,而不会留下任何点。

不仅关于匹配多行文字。

1 个答案:

答案 0 :(得分:0)

你需要修改两件事:1)添加DOTALL修饰符,因为你有跨越多行的文本和2)使用延迟点匹配或 - 更高效 - 否定字符类[^.]来匹配字符到.之后的第一个in

(?s)(I like to find )(.*)( in )([^.]*)(\.)(.*)
                               ^^^^^^^

请参阅regex demo

然而,最好的是this one

(?s)(I like to find )(.*?)( in )([^.]*)(\.)(.*)

不情愿(懒惰)量词使引擎在延迟量化的子模式和下一个子模式之间匹配尽可能少的字符。如果我们在.*之前使用( in ),则会发生回溯,也就是说,"I like to find "之后的整个字符串将被正则表达式引擎抓取,然后引擎将向后移动以查找< em> last in 。因此,使用.*?将匹配第一个 in

您可以使用[^.]*与不情愿的量词.来匹配第一个点,而不是*?,但由于引擎扩展子模式,因此性能方面更昂贵在尝试将字符串与后续子模式匹配时,每次失败都会遇到。

检查我对Perl regex matching optional phrase in longer sentence的回答,了解贪婪和懒惰(=不情愿)量词的工作原理。