[英]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.