我目前有以下正则表达式
ZL[^0-9].{16}_.{3}PAD_N.{26}\.PIC
匹配文件名如下
ZLF_1177_0771428479_534PAD_N0530130SALP09217_1100LMV01.PIC
但想改变正则表达式,使位置上的 9 个字符SALP09217
不能占用范围
SALP00000-00899, SALP01000-03099 and SALP05000-06999
(请注意SALT00000-00899
, 或除 之外的任何其他子字符串SALP
都是允许的,只有以 开头的子字符串SALP
才会被排除)
以下正则表达式部分有效
ZL[^0-9].{16}_.{3}PAD_N.{7}(?!(SALP00[0-8][0-9][0-9])|(SALP0[1-3]0[0-9][0-9])|(SALP0[5-6][0-9][0-9][0-9])).*\.PIC
但允许的字符串比原始正则表达式允许的字符串更大。例如,它允许
ZLF_1177_0771428479_534PAD_N0530130SALP09217_1100LMV01.PIC
这是正确的,但也是
ZLF_1177_0771428479_534PAD_N0530130SALP09217_1100LMV01LARGER.PIC
这不是
“理想”的正则表达式是
ZL[^0-9].{16}_.{3}PAD_N.{7}(?!(SALP00[0-8][0-9][0-9])|(SALP0[1-3]0[0-9][0-9])|(SALP0[5-6][0-9][0-9][0-9])).{10}\.PIC
但
ZLF_1177_0771428479_534PAD_N0530130SALP09217_1100LMV01.PIC
不会匹配。
有什么建议么?
14
最佳答案
3
您可以使用
ZL[^0-9].{16}_.{3}PAD_N.{7}(?!SALP0(?:0(?:0{0,2}[0-9]|0?[1-9][0-9]|[1-8][0-9]{2})|(?:100[0-9]|10[1-9][0-9]|1[1-9][0-9]{2}|2[0-9]{3}|30[0-9]{2})|(?:500[0-9]|50[1-9][0-9]|5[1-9][0-9]{2}|6[0-9]{3}))(?!\d)).{19}\.PIC
参见。
(?!SALP0(?:0(?:0{0,2}[0-9]|0?[1-9][0-9]|[1-8][0-9]{2})|(?:100[0-9]|10[1-9][0-9]|1[1-9][0-9]{2}|2[0-9]{3}|30[0-9]{2})|(?:500[0-9]|50[1-9][0-9]|5[1-9][0-9]{2}|6[0-9]{3})))
如果当前位置右侧紧邻 SALP00000-00899、SALP01000-03099 和 SALP05000-06999 范围,则负向前瞻匹配失败。
笔记:
SALP00(?:0{0,2}[0-9]|0?[1-9][0-9]|[1-8][0-9]{2})
匹配 SALP00000-00899,SALP0(?:100[0-9]|10[1-9][0-9]|1[1-9][0-9]{2}|2[0-9]{3}|30[0-9]{2})
匹配 SALP01000-03099 和SALP0(?:500[0-9]|50[1-9][0-9]|5[1-9][0-9]{2}|6[0-9]{3})
与 SALP05000-06999 匹配。(?!\d)
在前瞻中的替代方案之后,确保数字被完整检查,而不是部分检查,以便SALP00903
可以匹配诸如此类的值- 另外,看看我是如何将
.{26}
模式划分为.{7}
并使.{19}
前瞻工作起来的。
1
-
@CarySwoveland 这是由于前瞻中的替代方案部分匹配造成的,因此这是一个简单的修复。
–
|
鉴于 Wiktor 的专业知识,我无法判断他的回答是否是认真的。所需的负面前瞻可以写得更简单。
给定排除范围:
SALP00000-00899
SALP01000-03099
SALP05000-06999
SALP0
一切皆有开始和结束,这是显而易见的[0-9]{2}
。
则剩余两位数字为:
0[0-8]
1[0-9] 2[0-9] 30
5[0-9] 6[0-9]
可以重新分组:
0[0-8]
1[0-9] 2[0-9] 5[0-9] 6[0-9]
30
并合并为:0[0-8]|[1256][0-9]|30
。
因此,整个负面前瞻只是:
(?!SALP0(0[0-8]|[1256][0-9]|30)[0-9]{2})
如上所述,它通过在适当的偏移处一分为二来合并.{26}
。请注意,环视不消耗任何字符,因此总长度不会改变:
ZL[^0-9].{16}_.{3}PAD_N.{7}(?!SALP0(?:0[0-8]|[1256][0-9]|30)[0-9]{2}).{19}\.PIC
|
当且仅当字符串与以下正则表达式匹配时,它才有效。
(?x) # invoke extended (aka free-spacing) mode
^ # match beginning of string
ZL\D # match 'ZL' then a char other than a digit
.{16}_.{3} # match 16 characters other than line terminators
# (COTLTs), then literal then 3 CORTLs
PAD_N # match literal
\d{7} # match 7 digits
(?: # begin non-capture group
(?!SALP) # negative lookahead asserts that next 4 chars are not 'SALP'
.{9} # match 9 COTLTs
| # or
SALP # match literal
(?: # begin a non-capture group
009\d{2} # match a literal then 2 digits
| # or
03[1-9]\d{2} # match a literal then a char in the char case then 2 digits
| # or
0[4789]\d{3} # match a literal then char in char class then 3 digits
| # or
[1-9]\d{4} # match char in char class then 4 digits
) # end non-capture class
) # end non-capture class
_.{9} # match literal then 9 COTLTs
\.PIC$ # match literal at end of string
5
-
2这很可能是真正想要的,但从技术上讲,提供的规范允许
SALP
在这 9 个位置上使用非数字和非数字,但这个正则表达式不允许
–
-
user2175783,我修改了我的答案以符合您对问题的澄清。如果我对问题的理解仍然不正确,请告诉我。@jhnc,您说得对。
–
-
我不认为这种双重否定比直接说明什么是不允许的(你现在正在部分地这样做)更清楚或更不容易出错。你似乎遗漏了
SALP03[1-9][0-9]{2}
–
-
@jhnc,谢谢你指出我的疏忽。根据我对这个问题的新理解,我对 后面五位数字定义的“范围”可以采取的两种方法并不感兴趣
'SALP'
,但我认为在答案中(以及在你的评论中)同时体现这两种方法都是值得的。
– -
1我只是发现长代码令人困惑:-) 顺便说一句,你仍然缺少 032、033、034 等。
–
|
–
–
–
.*
你需要,.{19}
因为前瞻不消耗任何东西。你需要将 1000-3099 范围分成 1000-2999、3000-3099–
ZL[^0-9].{16}_.{3}PAD_N.{7}(?!SALP0(0[0-8]|[1256][0-9]|30)[0-9]{2}).{19}\.PIC
–
|