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)
)的开头,后跟0或更多重复的\A
+数字+0+空格,然后后跟字符串的结尾
-0+空格字符\s*
-匹配重置运算符放弃目前匹配的文本\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/