Java 正则表达式挂起程序(CPU使用率100%)

Java 正则表达式挂起程序(CPU使用率100%),java,regex,Java,Regex,当我使用下面的字符串作为正则表达式的输入时,Java的CPU使用率为100% 使用的正则表达式: 下面是我的应用程序中用于描述字段的正则表达式 ^([A-Za-z0-9\\-\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\.&\\\,]+[\\s]*)+ 用于测试的字符串: 来自提供商的SaaS服务VLAN_One 第二次尝试Didier SPT,因为他给我的第一次是错误的:-( 当我将同一个字符串拆分为不同的组合时,它可以正常工作。例如“提供者_One提供的SaaS服务VLAN”

当我使用下面的字符串作为正则表达式的输入时,Java的CPU使用率为100%

使用的正则表达式:

下面是我的应用程序中用于描述字段的正则表达式

^([A-Za-z0-9\\-\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\.&\\\,]+[\\s]*)+
用于测试的字符串:

来自提供商的SaaS服务VLAN_One
第二次尝试Didier SPT,因为他给我的第一次是错误的:-(

当我将同一个字符串拆分为不同的组合时,它可以正常工作。例如“提供者_One提供的SaaS服务VLAN”,“他给我的第一个错误:-(”,等等。Java只挂起上面给定的字符串

我还尝试优化正则表达式,如下所示

^([\\w\\-\\\.\\\&\\,]+[\\s]*)+

即使这样也不起作用。

首先,您需要意识到您的正则表达式无法与提供的输入字符串匹配。这些字符串包含许多不是“word”字符的字符(
'/':'
')

那为什么要花这么长时间

基本上是“灾难性回溯”。更具体地说,您的正则表达式的重复结构为正则表达式回溯算法提供了一个指数级的备选方案

你的正则表达式是这样说的:

  • 一个或多个单词字符
  • 后跟零个或多个空格字符
  • 尽可能多地重复前两种模式
  • 问题在于“零个或多个空格字符”部分。第一次,匹配器会将所有字符匹配到第一个意外字符(即
    ”,这是另一个经典的字符类型

    当正则表达式到达输入字符串中不属于字符类的
    时,嵌套的量词会导致检查大量排列(假设您使用的是
    .matches()
    方法)

    让我们将问题简化为以下正则表达式:

    ^([^:]+)+$
    
    这个字符串:

    1234:
    
    正则表达式引擎需要检查

    1234    # no repetition of the capturing group
    123 4   # first repetition of the group: 123; second repetition: 4
    12 34   # etc.
    12 3 4 
    1 234
    1 23 4
    1 2 34
    1 2 3 4
    
    …这仅仅是四个字符。在您的示例字符串中,RegexBuddy在100万次尝试后中止。Java将很高兴地继续发出声音…直到最后承认这些组合都不允许以下内容匹配:

    你怎么解决这个问题

    您可以使用以下命令禁止正则表达式回溯:

    将允许正则表达式更快地失败。顺便说一句,我删除了所有不必要的反斜杠

    编辑:

    一些测量:

    在字符串
    “was error:-)”
    上,需要执行RegexBuddy 862步骤才能找出不匹配项。
    对于
    “我错了:-)”
    ,这是1742个步骤。
    对于
    “给我的是错误的:-)”
    ,14014步。
    对于
    “他给我的是错误的:-)”
    ,28046步。
    对于
    “他给我的一个是错误的:-)”
    ,112222步。

    对于
    “他给我的第一个错误:-)”
    ,>1000000步

    为什么要将空格与其他字符分开匹配?为什么你要在比赛开始时锚定比赛,而不是在比赛结束时?如果要确保字符串不以空格开头或结尾,应执行以下操作:

    ^[A-Za-z0-9_.&,-]+(?:\s+[A-Za-z0-9_.&,-]+)*$
    
    现在,正则表达式引擎只能通过一条“路径”遍历字符串。如果在到达末尾之前,与
    [A-Za-z0-9.&]
    匹配的字符已用完,而下一个字符与
    \s
    不匹配,则会立即失败。如果它到达末尾时仍然匹配空白字符,那么它将失败,因为每次运行空白字符后,需要至少匹配一个非空白字符

    如果要确保只有一个空格字符分隔非空格的运行,只需从
    \s+
    中删除量词:

    ^[A-Za-z0-9_.&,-]+(?:\s[A-Za-z0-9_.&,-]+)*$
    
    如果您不关心空白相对于非空白的位置,只需将它们与相同的字符类匹配即可:

    ^[A-Za-z0-9_.&,\s-]+$
    
    我假设您知道您的正则表达式与给定的输入不匹配,因为笑脸中有
    ),您只想知道为什么失败需要这么长时间

    当然,由于您是以Java字符串文本的形式创建正则表达式,您可以编写:

    "^[A-Za-z0-9_.&,-]+(?:\\s+[A-Za-z0-9_.&,-]+)*$"
    


    (我知道您在最初的问题中有两个反斜杠,但这可能只是为了让它们正确显示,因为您没有使用SO出色的代码格式功能。)

    你想从该字符串中匹配或提取什么?你的正则表达式似乎基本上可以匹配任何句子。@user1531484-你可以发布整个代码,即模式、匹配器和要提取的代码吗?当你从字符串中删除笑脸和数字时,它能工作吗?你能发布用于此的java代码吗?现在有人已经发布了正则表达式解释了为什么会发生这种情况,我可以问你是否尝试过流处理方法吗?你需要保留
    @Thor84no:No.在字符类中,点意味着点。不必要的反斜杠对代码无害,但对眼睛有害。所有格量词禁止回溯。“如果你走到了这一步,并且有一个部分匹配,你就不能回头。如果你失败超过这一点,就放弃。”@user1531484:tripleee已经回答了你的问题;我已经添加了另一个到正则表达式大师Jan Goyvaerts的正则表达式教程的链接(到关于所有格量词的部分)。我强烈推荐整个教程。”^[a-Za-z0-9.&-]+(?:\\s[A-Za-z0-9.&,-]+)*$与原始字符串不匹配,因为它不会匹配具有两个连续空格的字符串。但是您的正则表达式“^[A-Za-z0-9.&,-]+(?:\\s+[A-Za-z0-9.&,-]+)*$”与Tim Pietzcker的所有格量词解决方案相比,我更喜欢它,后者太聪明了。:)
    "^[A-Za-z0-9_.&,-]+(?:\\s+[A-Za-z0-9_.&,-]+)*$"
    
    "^[A-Za-z0-9_.&,-]+(?:\\s[A-Za-z0-9_.&,-]+)*$"
    
    "^[A-Za-z0-9_.&,\\s-]+$"