【问题标题】:determine if regular expression only matches fixed-length strings判断正则表达式是否只匹配固定长度的字符串
【发布时间】:2011-04-07 08:30:15
【问题描述】:

有没有办法确定正则表达式是否只匹配固定长度的字符串? 我的想法是扫描 *,+ 和 ?然后,需要一些智能逻辑来寻找 {m,n} 其中 m!=n。 没有必要采取|考虑到运营商。
小例子:^\d{4} 是定长的; ^\d{4,5} 或 ^\d+ 是可变长度的

我正在使用 PCRE。

谢谢。

保罗·普拉特

【问题讨论】:

  • 用另一个正则表达式? :)
  • 肯定有必要考虑|。毕竟,正则表达式/ab|c/ 的固定长度是多少?
  • 别忘了 * \+ 和 \?需要忽略。还有包含这些字符的方括号,例如[+*?]
  • 解析正则表达式的正则表达式?现在你有三个问题!
  • @KennyTM:当然是的@Ani:这也是我的想法。 @Philip Potter:确实,好点,但正如我所提到的,我们不关心|运营商@JeremeP:是的,好点。我也会考虑到这一点。

标签: c regex pcre


【解决方案1】:

只是为了好玩。

假设我们测试的正则表达式仅支持+*?{m,n}{n}[...](除了一些奇怪的语法,如[]][^]])。那么正则表达式只有在遵循语法时才是固定长度的:

 REGEX     -> ELEMENT *
 ELEMENT   -> CHARACTER ( '{' ( \d+ ) ( ',' \1 )? '}' )?
 CHARACTER -> [^+*?\\\[] | '\\' . | '[' ( '\\' . | [^\\\]] )+ ']'

在 PCRE 中可以改写为:

^(?:(?:[^+*?\\\[{]|\\.|\[(?:\\.|[^\\\]])+\])(?:\{(\d+)(?:,\1)?\})?)*$

【讨论】:

  • 我承认我不知道你的意思 ;-) 你的意思是正则表达式本身应该匹配上面的表达式吗?
【解决方案2】:

根据regular-expressions.info,PCRE 引擎仅支持固定长度的正则表达式和lookbehinds 内的交替。

所以如果你有一个有效的正则表达式,用(?<=) 包围它,看看它是否仍然可以编译。然后你知道它要么是固定大小的,要么是固定大小的正则表达式的交替。

我不确定a(b|cd)e 之类的东西 - 这绝对不是固定大小的,但它仍然可以编译。您需要尝试一下(我没有安装 C/PCRE)。

【讨论】:

    【解决方案3】:

    好吧,您可以利用 Python 的正则表达式引擎仅允许在后向断言中使用固定长度的正则表达式这一事实:

    import re
    regexes = [r".x{2}(abc|def)", # fixed
               r"a|bc",           # variable/finite
               r"(.)\1",          # fixed
               r".{0,3}",         # variable/finite
               r".*"]             # variable/infinite
    
    for regex in regexes:
        try:
            r = re.compile("(?<=" + regex + ")")
        except:
            print("Not fixed length: {}".format(regex))
        else:
            print("Fixed length: {}".format(regex))
    

    会输出

    Fixed length: .x{2}(abc|def)
    Not fixed length: a|bc
    Fixed length: (.)\1
    Not fixed length: .{0,3}
    Not fixed length: .*
    

    我假设正则表达式本身是有效的。

    现在,Python 如何知道正则表达式是否是固定长度的?只需阅读源代码 - 在 sre_parse.py 中,有一个名为 getwidth() 的方法返回一个由可能的最低和最高长度组成的元组,如果在后向断言中它们不相等,re.compile() 将引发错误. getwidth() 方法递归遍历正则表达式:

    def getwidth(self):
        # determine the width (min, max) for this subpattern
        if self.width:
            return self.width
        lo = hi = 0
        UNITCODES = (ANY, RANGE, IN, LITERAL, NOT_LITERAL, CATEGORY)
        REPEATCODES = (MIN_REPEAT, MAX_REPEAT)
        for op, av in self.data:
            if op is BRANCH:
                i = sys.maxsize
                j = 0
                for av in av[1]:
                    l, h = av.getwidth()
                    i = min(i, l)
                    j = max(j, h)
                lo = lo + i
                hi = hi + j
            elif op is CALL:
                i, j = av.getwidth()
                lo = lo + i
                hi = hi + j
            elif op is SUBPATTERN:
                i, j = av[1].getwidth()
                lo = lo + i
                hi = hi + j
            elif op in REPEATCODES:
                i, j = av[2].getwidth()
                lo = lo + int(i) * av[0]
                hi = hi + int(j) * av[1]
            elif op in UNITCODES:
                lo = lo + 1
                hi = hi + 1
            elif op == SUCCESS:
                break
        self.width = int(min(lo, sys.maxsize)), int(min(hi, sys.maxsize))
        return self.width
    

    【讨论】:

    • 我正在用 C 语言编写代码,使用 PCRE 库...谢谢 :-)
    猜你喜欢
    • 2018-11-24
    • 2019-01-04
    • 2015-04-02
    • 1970-01-01
    • 1970-01-01
    • 2022-08-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多