繁体   English   中英

正则表达式匹配和限制字符类

[英]Regex to match and limit character classes

我不确定使用Regex是否可行,但我希望能够根据不同的字符限制允许的下划线数量。 这是为了将疯狂的通配符限制限制为用Java编写的搜索引擎。

起始字符是字母数字。 但是如果有更多的下划线而不是前面的字符,我基本上想要一个匹配。 所以

BA_会很好但是BA___会匹配正则表达式并且会被踢出查询解析器。

这可能使用正则表达式吗?

是的,你可以做到。 : 只有当下划线少于字母时,此模式才会成功

^(?:[A-Z](?=[A-Z]*(\\1?+_)))*+[A-Z]+\\1?$

否定版本:

^(?:[A-Z](?=[A-Z]*(\\1?+_)))*\\1?_*$

我们的想法是重复一个包含对自身的反向引用+下划线的捕获组。 在每次重复时,捕获组都在增长。 ^(?:[AZ](?=[AZ]*+(\\\\1?+_)))*+将匹配具有对应下划线的所有字母。 您只需添加[AZ]+以确保有更多字母,并使用\\\\1?完成您的模式\\\\1? 包含所有下划线(我将其设为可选,以防根本没有下划线)。

请注意,如果在第一个模式中将[AZ]+替换为[AZ]{n} ,则可以精确设置字母和下划线之间的字符数差异。


为了给出一个更好的想法,我将尝试逐步描述它如何与字符串ABC-- (因为不可能将下划线以粗体显示,我使用连字符代替):


ABC--        ^(?:[A-Z](?=[A-Z]*(\1?+-)))*+[A-Z]+\1?$

ABC--        ^(?:[A-Z](?=[A-Z]*(\1?+-)))*+[A-Z]+\1?$
ABC--        ^(?:[A-Z](?=[A-Z]*(\1?+-)))*+[A-Z]+\1?$

ABC--        ^(?:[A-Z](?=[A-Z]*(\1?+-)))*+[A-Z]+\1?$
 
ABC--        ^(?:[A-Z](?=[A-Z]*(\1?+-)))*+[A-Z]+\1?$

ABC--        ^(?:[A-Z](?=[A-Z]*(\1?+-)))*+[A-Z]+\1?$

ABC--        ^(?:[A-Z](?=[A-Z]*(\1?+-)))*+[A-Z]+\1?$
 
ABC--        ^(?:[A-Z](?=[A-Z]*(\1?+-)))*+[A-Z]+\1?$

ABC--        ^(?:[A-Z](?=[A-Z]*(\1?+-)))*+[A-Z]+\1?$
 
ABC--        ^(?:[A-Z](?=[A-Z]*(\1?+-)))*+[A-Z]+\1?$

ABC--        ^(?:[A-Z](?=[A-Z]*(\1?+-)))*+[A-Z]+\1?$
 
ABC--        ^(?:[A-Z](?=[A-Z]*(\1?+-)))*+[A-Z]+\1?$
 
ABC--        ^(?:[A-Z](?=[A-Z]*(\1?+-)))*+[A-Z]+\1?$

ABC--        ^(?:[A-Z](?=[A-Z]*(\1?+-)))*+[A-Z]+\1?$
 
ABC--        ^(?:[A-Z](?=[A-Z]*(\1?+-)))*+[A-Z]+\1?$
 
ABC--        ^(?:[A-Z](?=[A-Z]*(\1?+-)))*+[A-Z]+\1?$
 
ABC--        ^(?:[A-Z](?=[A-Z]*(\1?+-)))*+[A-Z]+\1?$


注意:需要使用非捕获组的占有量词来避免错误结果。

示例: ABC---和模式: ^(?:[AZ](?=[AZ]*(\\1?+-)))*[AZ]+\\1?$


ABC---     ^(?:[A-Z](?=[A-Z]*(\1?+-)))*[A-Z]+\1?$
 
ABC---     ^(?:[A-Z](?=[A-Z]*(\1?+-)))*[A-Z]+\1?$
 
ABC---     ^(?:[A-Z](?=[A-Z]*(\1?+-)))*[A-Z]+\1?$

问题:捕获组中有多少个连字符?
答:总是三个!

如果重复的非捕获组返回一个字母,捕获组总是包含三个连字符(正如最后一次正则表达式引擎读取捕获组)。这是违反直觉的,但是合乎逻辑的。

$pattern = <<<'EOD'
~
 (?(DEFINE)
     (?<neutral> (?: _ \g<neutral>?+ [A-Z] | [A-Z] \g<neutral>?+ _ )+ )
 )

 \A (?: \g<neutral> | _ )+ \z
~x
EOD;

var_dump(preg_match($pattern, '____ABC_DEF___'));

Robby Pond在评论中问我如何找到下划线比字母更多的字符串(所有这些都不是下划线) 显然,最好的方法是计算下划线的数量并与字符串长度进行比较。 但是关于完整的正则表达式解决方案,由于模式需要使用递归功能,因此无法使用Java构建模式。 例如,你可以用PHP做到这一点:

 $pattern = <<<'EOD' ~ (?(DEFINE) (?<neutral> (?: _ \\g<neutral>?+ [AZ] | [AZ] \\g<neutral>?+ _ )+ ) ) \\A (?: \\g<neutral> | _ )+ \\z ~x EOD; var_dump(preg_match($pattern, '____ABC_DEF___')); 

它在单数正则表达式中是不可能的。

i)需要实现逻辑以获得下划线之前的字符数(应该编写正则表达式以在下划线之前获得字符)。

ii)并验证结果(字符数 - 1)=所遵循的分号数(正则表达式返回下划线后跟字符)。

编辑:当! 我刚刚注意到你需要这个用于java。 无论如何......如果来自.Net世界的人偶然发现这篇文章,我就把它留在这里。

如果您使用.Net,则可以使用平衡组

^(?:(?<letter>[^_])|(?<-letter>_))*(?(letter)(?=)|(?!))$

.net正则表达式引擎能够维护捕获的组中的所有捕获模式。 在其他类型中,捕获的组将始终包含最后匹配的模式,但在.net中,所有先前的匹配都包含在捕获集合中供您使用。 此外,.net引擎还能够使用?<group-name>?<-group-name>构造来推送和弹出捕获的组的堆栈。 这两个方便的结构可用于匹配paranthesis对等。

在上面的正则表达式中,引擎从字符串的开头开始,并尝试匹配“_”以外的任何内容。 这当然可以改为适合你的任何东西(例如[AZ][az] )。 交替基本上意味着匹配[^\\_][\\_]并且这样做可以从捕获的组中推送或弹出。

正则表达式的后半部分是条件(?(group-name)true|false) 它基本上说,如果该组仍然存在(比弹出更多推送),那么执行true部分,如果不执行false部分。 使模式匹配的最简单方法是使用空的正向前看: (?=)并且使其失败的最简单方法是(?!) ,这是一个负前瞻。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM