我正在尝试匹配以一个或两个1开头的任何数字,但是如果紧跟在那之后的一个或两个1,那么就没有。
我希望Regex符合以下条件:
1, 12, 11, 123, 111, 1113, 1123, 143, 1153, etc.
但我希望正则表达式不匹配:
0, 01, 21, 13, 113, 134, 11333, 135655..., etc.
正如你所看到的,数字必须从1开始。它可以从一个1或两个1开始,但它必须以至少一个1开始。在1(s)之后,不能有一个3.之后一个或两个1,如果1之后没有3,则可以有任意数字(1632362382983598235有效)。
我尝试了以下模式(以及更多模式),但它们都不起作用:
re.fullmatch(r'^1{1,2}[^3].*','113') # This matches '113' (it shouldn't), doesn't match '13' (as it shouldn't), but it also doesn't match '1' (it should)
re.fullmatch(r'^(11[^3]|1[^3]).*','113') # Same as above
re.fullmatch(r'^(11(?!3))|(1(?!3)).*','113') # This one actually allows '1', but it still allows '113'
(我知道'。*'匹配任何字符,而不仅仅是数字。)
我做错了什么?
答案 0 :(得分:1)
这可以完成工作(try it):
(^1{1,2}[^13].*)|(^1{3}.*)|^1{1,2}
左边部分包括从1或2开始的情况(并确保1和3都不跟随);中间部分涵盖了从3个开始的情况(然后我们不关心接下来的事情);正确的部分包括' 1'和' 11'。
答案 1 :(得分:1)
如果我效仿WiktorStribiżew基于setTimeout(doParsing, 0)
的方法,并且避开re.match()
,那么为什么以下明显的简单模式不能满足需要:
re.fullmatch()
即。如果数字以1以外的数字开头,或以13开头或以113开头,则拒绝它。我们依靠这种模式来简单地拒绝坏的前缀,不一定完全接受好的数字。
这个问题是否需要“原子组/占有量词解决方法”?
答案 2 :(得分:1)
我想我找到了一个更好的解决方案(至少对我的需求而言)。我使用了负面预测:
^(?!1{1,2}3)1{1,2}.*
说明:
^ # Beginning of string
(?!1{1,2}3) # Don't match if ^ is followed by one or two 1s and a 3
1{1,2} # One to two 1s
.* # Anything else is accepted
最好的部分是它与perigon的答案相同,但它更短,更容易阅读,更容易适应。
修改强>
cdlane部分给了我一个很棒的解决方案。我将它改编为re.fullmatch
,它比我原来的1个字节更容易适应和缩短:
^(?![^1]|1{1,2}3).*
说明:
^ # Beginning of string
(?! # Do not match if
[^1] # The string starts with anything other than 1
|1{1,2}3) # Or there is one or two 1s followed by a 3
.* # Anything else is accepted
对于任何感兴趣的人,您还可以通过插入以下内容轻松限制最初可能出现的1的数量:
|1{limit,}
像这样:
^(?![^1]|1{1,2}3|1{3,}).*
如果你想改变必须出现的1的数量,而不是:
[^1]
使用:
(?!1{minimum,}
把它放在一起:
^(?!(?!1{4,})|1{4,5}3|1{6,}).*
答案 3 :(得分:0)
您可以在此处使用原子组/占有量词解决方法。它涉及一个积极的前瞻,在其模式周围有一个捕获组,然后是对该值的反向引用。它会阻止回溯到11?
,而负向前瞻只会在3
或1
之后检查11
:
^(?=(11?))\1(?!3)
请参阅regex demo
<强>详情
^
- 字符串开头(?=(11?))
- 如果在字符串的开头有1
或11
,则会检查(但不会推进其索引或将捕获的值添加到匹配值)并将值捕获到第1组\1
- 对第1组值的反向引用(现在,它是原子的,不会回溯到模式中(这是模式的问题)(?!3)
- 如果在当前位置右侧立即发现3
,则表示匹配失败的否定前瞻。在Python中,使用原始字符串文字声明正则表达式:
import re
rx = r'(?=(11?))\1(?!3)'
s = '113'
m = re.match(rx, s)
if m:
print("Valid")
else:
print("Invalid")
查看online demo。请注意,^
无需与re.match
一起使用,因为该方法仅在字符串的开头找到匹配项。