Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/ruby/23.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Ruby 用于查找最多n个连续模式的正则表达式_Ruby_Regex - Fatal编程技术网

Ruby 用于查找最多n个连续模式的正则表达式

Ruby 用于查找最多n个连续模式的正则表达式,ruby,regex,Ruby,Regex,假设我们的模式是大写字母的正则表达式(但我们可能有一个比搜索大写字母更复杂的模式) 要找到至少n个连续的模式(在本例中,我们正在寻找的模式只是一个大写字母),我们可以这样做: (使用Ruby) 但是,如何搜索最多n个连续模式,例如,最多一个连续大写字母: matches = somestring.scan(/ ??? /) => [" deFgHij kLmN pQrS ", " abcdEf"] 详细策略 我读到我需要否定“至少”正则表达式,通过将其转换为DFA,否定接受状态(然后将

假设我们的模式是大写字母的正则表达式(但我们可能有一个比搜索大写字母更复杂的模式)

要找到至少n个连续的模式(在本例中,我们正在寻找的模式只是一个大写字母),我们可以这样做:

(使用Ruby)

但是,如何搜索最多n个连续模式,例如,最多一个连续大写字母:

matches = somestring.scan(/ ??? /)
=> [" deFgHij kLmN pQrS ", " abcdEf"]

详细策略 我读到我需要否定“至少”正则表达式,通过将其转换为DFA,否定接受状态(然后将其转换回NFA,尽管我们可以),从而将其写成正则表达式。如果我们认为遇到的模式是接收“1”,而没有接收到的模式是接收“0”,那么我们可以绘制一个简单的DFA图(其中n=1,我们最多需要一个模式):

具体来说,我想知道这是如何变成正则表达式的。一般来说,我希望找到如何找到“最多”与正则表达式,因为我的正则表达式技能感到发育不良与“至少”单独


绊倒危险-精神上不是很正确的解决方案 请注意,该问题不是重复的,因为使用公认的方法会给出:

somestring.scan(/[A-Z]{2}[A-Z]*(.*)[A-Z]{2}[A-Z]*/)
=> [[" deFgHij kLmN pQrS X"]]
这不是DFA所显示的,不仅仅是因为它错过了第二个寻求的匹配-更重要的是,它包括了“X”,它不应该包括,因为“X”后面跟着另一个资本,从DFA中我们可以看到,后面跟着另一个资本的资本不是接受状态

你可以建议

somestring.split(/[A-Z]{2}[A-Z]*/)
=> ["", " deFgHij kLmN pQrS ", " abcdEf"]
(感谢)

但我仍然想知道如何单独使用regex查找最多n个实例。(了解一下!)

要查找带有正则表达式的“至多”,可以使用后缀
{1,n}
(可能前面有一个负的lookback,后面有一个正的lookahead),因此您需要的是:

irb(main):006:0> somestring.scan(/[A-Z]{1,2}/)
=> ["AB", "C", "F", "H", "L", "N", "Q", "S", "XY", "Z", "E"]

(但是,正则表达式在字符串的开头和结尾可能不匹配)

看来

irb(main):026:0> somestring.split(/[A-Z]{3,}/)                                                                                                       
=> ["", " deFgHij kLmN pQrS ", " abcdEf"]
这样会更好。

为什么您的尝试无效 您当前的尝试存在一些问题

  • X
    是匹配的一部分的原因是
    *
    贪婪并尽可能多地消耗-因此,只留下所需的两个大写字母由尾随位匹配。这可以用一个非贪婪的量词来解决
  • 你没有获得第二场比赛的原因有两个。首先,需要有两个尾随的大写字母,但这里是字符串的结尾。其次,匹配不能重叠。第一个匹配包括至少两个尾随大写字母,但第二个需要在开始时再次匹配,这是不可能的
  • 还有更多隐藏的问题:尝试输入四个连续的大写字母-它可以给你一个空匹配(如果你使用非贪婪的量词-贪婪的一个有更严重的问题)
  • 用当前的方法修复所有这些问题是很困难的(我尝试过,但失败了——如果你想看到我的尝试,请查看本文的编辑历史,直到我决定完全放弃这种方法)。那我们试试别的吧

    寻找另一个解决方案 我们想要匹配的是什么?忽略边缘情况,即匹配从字符串的开头开始或在字符串的结尾结束,我们希望匹配:

    (非上限)1个上限(非上限)1个上限(非上限).

    这是杰弗里·弗里德尔的理想选择。看起来像

    [^A-Z]+(?:[A-Z][^A-Z]+)*
    
    那么边缘案例呢?我们可以这样说:

  • 我们希望允许在匹配的开头有一个大写字母,只要它位于字符串的开头
  • 我们希望允许在匹配结束时使用一个大写字母,前提是它位于字符串的末尾
  • 要将这些添加到我们的模式中,我们只需将大写字母与适当的锚定组合,并将两者标记在一起作为可选:

    (?:^[A-Z])?[^A-Z]+(?:[A-Z][^A-Z]+)*(?:[A-Z]$)?
    
    更妙的是,我们不再需要捕捉了

    推广解决方案 通过将每个
    [A-Z]
    更改为
    [A-Z]{1,n}
    ,可以很容易地将此解决方案推广到“最多n个连续大写字母”的情况,从而允许最多
    n个
    大写字母,而到目前为止只允许一个

    tl;博士 要匹配最多包含
    N
    PATTERN
    s的单词,请使用正则表达式

    /\b(?:\w(?:(?<!PATTERN)|(?!(?:PATTERN){N,})))+\b/
    
    现在,重新运行至少2个大写的正则表达式返回

    at_least_2_capitals = somestring.scan(/[A-Z][A-Z]+/)
    => ["ABC", "XYZ", "DC", "DC", "TT"]
    
    => 
    
    注意完整的单词是如何被捕获的!你确定这就是你想要的吗?当然,我这样问是因为在后面的示例中,最多1个大写正则表达式返回完整的单词,而不仅仅是捕获的大写字母


    解决方案 不管怎样,这都是解决办法

    首先,为了只匹配模式(而不是整个单词,与您最初的示例一致),这里有一个用于最多-
    N
    -
    PATTERN
    s的正则表达式:

    进一步举例说明,最多2个大写regex返回

    at_least_2_capitals = somestring.scan(/[A-Z][A-Z]+/)
    => ["ABC", "XYZ", "DC", "DC", "TT"]
    
    => 
    

    最后,如果您想匹配最多包含一定数量连续模式的整个单词,那么这里有一种完全不同的方法:

    /\b(?:\w(?:(?<![A-Z])|(?![A-Z]{1,})))+\b/
    
    一般形式是

    /\b(?:\w(?:(?<!PATTERN)|(?!(?:PATTERN){N,})))+\b/
    
    /\b(?:\w(?)?
    

    您可以在中看到所有这些示例。

    如何从Q3到Q4?已修复。我重写得很整齐,但没有找到标签!由于缺乏简洁的解释,我忽略了尝试解释epsilon(字符串末尾)计为“0”在图中,表示接受以一个大写字母结尾的内容。你看过OPs示例输入了吗?这不是他要找的。他想找到最长的子字符串,这些子字符串包含的子模式的连续匹配项不超过
    n
    。他明确地说我认为他的示例输入/输出是嗯(与使用拆分和匹配其他内容相反)。抱歉,这不清楚!我的意思是,如何获得=>[“deFgHij kLmN pQrS”,“abcdEf mixedCa”
    /(?<!PATTERN)(?!(?:PATTERN){N+1,})(?:PATTERN)+/
    
    /(?<![A-Z])(?!(?:[A-Z]){2,})(?:[A-Z])+/
    
    => ["F", "H", "L", "N", "Q", "S", "E", "C", "DC", "I", "C", "I", "DC", "T", "TT"]
    
    => 
    
    /\b(?:\w(?:(?<![A-Z])|(?![A-Z]{1,})))+\b/
    
    ["deFgHij", "kLmN", "pQrS", "abcdEf", "mixedCaps", "mIxedCaps", "T", "t", "tt"]
    
    /\b(?:\w(?:(?<!PATTERN)|(?!(?:PATTERN){N,})))+\b/