Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/regex/19.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
Regex 如何在提取匹配项时验证Ruby中字符串的格式? 我想要什么_Regex_Ruby - Fatal编程技术网

Regex 如何在提取匹配项时验证Ruby中字符串的格式? 我想要什么

Regex 如何在提取匹配项时验证Ruby中字符串的格式? 我想要什么,regex,ruby,Regex,Ruby,验证字符串是否与此格式匹配:/^(#\d\s*)+$/(例如#1#2) 用散列法抓取所有的数字,比如#。它不必是MatchData对象,任何类型的数组、可枚举都可以 我的问题 使用匹配时,它只匹配上一次出现的事件: /^(#\d\s*)+$/.match“#1#2” # => # 当我使用扫描时,它“工作”: “#1#2”。扫描/#\d/ # => ["#1", "#2"] 但是我不相信我能验证字符串的格式,因为它将返回相同的“aaa#1#2” 问题 仅使用1个方法调用,我是否可以同时验证

验证字符串是否与此格式匹配:
/^(#\d\s*)+$/
(例如
#1#2

  • 用散列法抓取所有的数字,比如
    #
    。它不必是MatchData对象,任何类型的数组、可枚举都可以

  • 我的问题 使用
    匹配时
    ,它只匹配上一次出现的事件:

    /^(#\d\s*)+$/.match“#1#2”
    # => #
    
    当我使用扫描时,它“工作”:

    “#1#2”。扫描/#\d/
    # => ["#1", "#2"]
    
    但是我不相信我能验证字符串的格式,因为它将返回相同的
    “aaa#1#2”

    问题 仅使用1个方法调用,我是否可以同时验证我的字符串是否匹配
    /^(#\d\s*)+$/
    ,并获取
    #number
    的所有实例

    问这个问题我有点难过,因为我已经使用ruby一段时间了。这似乎很简单,但我无法实现。

    是的,您可以使用

    s.scan(/(?:\G(?!\A)|\A(?=(?:#\d\s*)*\z))\s*\K#\d/)
    

    详细信息

    • (?:\G(?!\A)|\A(?=(?:#\d\s*)*\z))
      -两个备选方案:
      • \G(?!\A)
        -上一次成功匹配的结束
      • |
        -或
      • \A(?=(?:#\d\s*)*\z)
        -字符串(
        \A
        )的开头,后跟0或更多重复的
        +数字+0+空格,然后后跟字符串的结尾
    • \s*
      -0+空格字符
    • \K
      -匹配重置运算符放弃目前匹配的文本
    • #\d
      -一个
      #
      字符,然后是一个数字
    简言之:首先匹配字符串的起始位置,但仅当右侧的字符串(即整个字符串)与所需的模式匹配时才匹配。由于该检查是通过向前看执行的,因此正则表达式索引保持在原来的位置,并且只有在使用
    \G
    运算符进行有效匹配之后,才会始终进行匹配(它匹配字符串的开头或上一个匹配的结尾,因此
    (?!\a)
    用于减去开始字符串的位置)

    :

    请注意,正则表达式仅取决于字符串中字符
    “#”
    的实例数。由于两个示例中的数字均为3,因此相应的正则表达式相等,即:

    /\A(#\d)\s*(#\d)\s*(#\d)\s*\z/
    
    这个正则表达式的构造如下

    str = "#1#2 #3 "
    n = str.count('#')
      #=> 3
    s = "(#\\d)\\s*"*n
      #=> "(#\\d)\\s*(#\\d)\\s*(#\\d)\\s*" 
    /\A#{s}\z/ 
      #=> /\A(#\d)\s*(#\d)\s*(#\d)\s*\z/ 
    
    def doit(str)
      r = /\A#{"(?:#?(\\d)(?=#|\\s+|\\z)\\s*)"*str.count('0123456789')}\z/
      str.match(r)&.captures
    end
    
    doit "1 2 #3 "     #=> ["1", "2", "3"] 
    doit "1 2 #3 "     #=> ["1", "2", "3"] 
    doit "1#2"         #=> ["1", "2"] 
    doit " #1 2 #3 "   #=> nil   
    doit "#1 2# 3 "    #=> nil 
    doit " #1 23 #3 "  #=> nil 
    
    正则表达式的内容是:“匹配字符串的开头,然后是三个相同的捕获组,每个捕获组后面可选地跟空格,然后是字符串的结尾。因此,正则表达式既测试字符串的有效性,又提取捕获组中所需的匹配项

    如果没有匹配项(
    match
    返回
    nil
    ),则需要使用,
    &

    OP的注释是对问题的概括,其中磅字符(
    “#”
    )是可选的

    str = "#1#2 #3 "
    n = str.count('#')
      #=> 3
    s = "(#\\d)\\s*"*n
      #=> "(#\\d)\\s*(#\\d)\\s*(#\\d)\\s*" 
    /\A#{s}\z/ 
      #=> /\A(#\d)\s*(#\d)\s*(#\d)\s*\z/ 
    
    def doit(str)
      r = /\A#{"(?:#?(\\d)(?=#|\\s+|\\z)\\s*)"*str.count('0123456789')}\z/
      str.match(r)&.captures
    end
    
    doit "1 2 #3 "     #=> ["1", "2", "3"] 
    doit "1 2 #3 "     #=> ["1", "2", "3"] 
    doit "1#2"         #=> ["1", "2"] 
    doit " #1 2 #3 "   #=> nil   
    doit "#1 2# 3 "    #=> nil 
    doit " #1 23 #3 "  #=> nil 
    
    对于包含三位数字的字符串,正则表达式为:


    虽然这个正则表达式确实可能相当长,但这并不一定意味着它会相对低效,因为lookaheads是相当本地化的。

    好吧,你搞定了。但至少答案并不那么明显,不会让我为没有想到它而感到难过;)实际上,我几乎想使用si在现实生活中,两步方法更可取,因为它更具可读性。因为Ruby不公开每个组捕获堆栈(就像在.NET或Python PyPi
    regex
    模块中一样,您不得不求助于这种变通方法,或者两步验证+提取方法。
    \G
    ,我在Ruby文档中找不到它,它似乎非常有用。我承认我仍然不完全理解它的效果(但会努力的)@CarySwoveland请参见和。基本上,它有助于将匹配锚定到字符串的开头,或使正则表达式仅匹配连续的匹配。与前瞻性一起,
    \G
    是一个完美的解决方案,可以在一些分隔子字符串中多次匹配某些模式,如果它们不同。如果分隔符相同,则无法工作(例如,双引号之间).谢谢,威克托。泰山和简的例子特别有用。这是一个有趣的方式,谢谢。我确实简化了我的问题,我的输入可以是字符串,如
    #1,2,#3
    ,或
    12#3
    等,所以这不是我的案例的最佳方法。无论如何,谢谢。我们不能读心术;@Wiktor的也不是答案适用于你的“真实”"问题。我修改了我的答案,以处理您给出的更一般的情况。我还简化了您原始问题的答案。顺便说一句,在简化实际问题时要小心;可能无法修改简化版本的解决方案以解决实际问题。主要是,我发现这两个版本的问题都很有趣,pr为小灰色细胞提供了良好的锻炼。当然,你不可能是读心术的人,但我希望得到的答案不仅适用于我的具体案例,而且适用于我需要匹配字符串并提取所有匹配数据的每一个案例。因此,我认为我不需要提供确切的用例。事实证明,这比预期的要难一些。
    /\A(?:#?(\d)(?=#|\s+|\z)\s*)(?:#?(\d)(?=#|\s+|\z)\s*)(?:#?(\d)(?=#|\s+|\z)\s*)\z/