【问题标题】:Need Regex for to match special situations需要正则表达式来匹配特殊情况
【发布时间】:2010-05-18 09:16:40
【问题描述】:

我正在拼命寻找匹配这些场景的正则表达式:

1) 匹配交替字符

我有一个类似“这是我的 foobababababaf 字符串”的字符串 - 我想匹配“babababa”

我只知道要搜索的片段的长度 - 我不知道可能是什么字符/数字 - 但它们是交替的。

我真的不知道从哪里开始:(

2) 匹配组合组

在像“这是我的 foobaafoobaaaooo 字符串”这样的字符串中 - 我想匹配“aaaooo”。就像 1) 我不知道可能是什么字符/数字。我只知道他们会分两组出现。

我尝试使用 (.)\1\1\1(.)\1\1\1 和类似的东西......

【问题讨论】:

  • 您使用什么语言或正则表达式风格?
  • 我目前正在使用 preg_match / preg_match_all 使用 PHP,所以它是 PCRE(PCRE 库版本 => 7.8 2008-09-05)。

标签: php regex pcre


【解决方案1】:

我认为这就是你想要的。

对于交替字符:

(?=(.)(?!\1)(.))(?:\1\2){2,}

\0 将是整个交替序列,\1\2 是两个(不同的)交替字符。

对于连续 N 和 M 个字符,可能由其他字符分隔(在此处将 NM 替换为数字):

(?=(.))\1{N}.*?(?=(?!\1)(.))\2{M}

\0 将是整个匹配,包括中缀。 \1 是重复(至少)N 次的字符,\2 是重复(至少)M 次的字符。

这是一个 Java 测试工具。

import java.util.regex.*;

public class Regex3 {
    static String runNrunM(int N, int M) {
        return "(?=(.))\\1{N}.*?(?=(?!\\1)(.))\\2{M}"
            .replace("N", String.valueOf(N))
            .replace("M", String.valueOf(M));
    }
    static void dumpMatches(String text, String pattern) {
        Matcher m = Pattern.compile(pattern).matcher(text);
        System.out.println(text + " <- " + pattern);
        while (m.find()) {
            System.out.println("  match");
            for (int g = 0; g <= m.groupCount(); g++) {
                System.out.format("    %d: [%s]%n", g, m.group(g));
            }
        }
    }
    public static void main(String[] args) {
        String[] tests = {
            "foobababababaf foobaafoobaaaooo",
            "xxyyyy axxayyyya zzzzzzzzzzzzzz"
        };
        for (String test : tests) {
            dumpMatches(test, "(?=(.)(?!\\1)(.))(?:\\1\\2){2,}");
        }
        for (String test : tests) {
            dumpMatches(test, runNrunM(3, 3));
        }
        for (String test : tests) {
            dumpMatches(test, runNrunM(2, 4));
        }
    }
}

这会产生以下输出:

foobababababaf foobaafoobaaaooo <- (?=(.)(?!\1)(.))(?:\1\2){2,}
  match
    0: [bababababa]
    1: [b]
    2: [a]
xxyyyy axxayyyya zzzzzzzzzzzzzz <- (?=(.)(?!\1)(.))(?:\1\2){2,}
foobababababaf foobaafoobaaaooo <- (?=(.))\1{3}.*?(?=(?!\1)(.))\2{3}
  match
    0: [aaaooo]
    1: [a]
    2: [o]
xxyyyy axxayyyya zzzzzzzzzzzzzz <- (?=(.))\1{3}.*?(?=(?!\1)(.))\2{3}
  match
    0: [yyyy axxayyyya zzz]
    1: [y]
    2: [z]
foobababababaf foobaafoobaaaooo <- (?=(.))\1{2}.*?(?=(?!\1)(.))\2{4}
xxyyyy axxayyyya zzzzzzzzzzzzzz <- (?=(.))\1{2}.*?(?=(?!\1)(.))\2{4}
  match
    0: [xxyyyy]
    1: [x]
    2: [y]
  match
    0: [xxayyyy]
    1: [x]
    2: [y]

说明

  • (?=(.)(?!\1)(.))(?:\1\2){2,} 有两个部分
    • (?=(.)(?!\1)(.)) 使用前瞻建立 \1\2
      • 嵌套的负前瞻确保\1 != \2
      • 使用前瞻捕获让\0 拥有整个匹配项(而不仅仅是“尾”端)
    • (?:\1\2){2,} 捕获 \1\2 序列,该序列必须至少重复两次。
  • (?=(.))\1{N}.*?(?=(?!\1)(.))\2{M} 包含三个部分
    • (?=(.))\1{N} 在前瞻中捕获 \1,然后匹配它 N
      • 使用前瞻捕获意味着重复可以是N 而不是N-1
    • .*? 允许使用中缀来分隔两个运行,但不愿意让它尽可能短
    • (?=(?!\1)(.))\2{M}
      • 类似于第一部分
      • 嵌套的负前瞻确保\1 != \2

运行正则表达式将匹配更长的运行,例如run(2,2) 匹配 "xxxyyy":

xxxyyy <- (?=(.))\1{2}.*?(?=(?!\1)(.))\2{2}
  match
    0: [xxxyy]
    1: [x]
    2: [y]

此外,它不允许重叠匹配。即"xx11yyy222"中只有一个run(2,3)

xx11yyy222 <- (?=(.))\1{2}.*?(?=(?!\1)(.))\2{3}
  match
    0: [xx11yyy]
    1: [x]
    2: [y]

【讨论】:

    【解决方案2】:

    假设你使用 perl/PCRE:

    1. (.{2})\1+((.)(?!\2)(.))\1+。第二个正则表达式会阻止匹配 oooo 之类的内容。

    UPD:那么 2. 将是 ((.)\2{N}).*?((?!\2)(.)\4{M})。如果您想获得类似 oooaoooo 的匹配项,请删除 (?!\2),并将 N 和 M 替换为 n-1 和 m-1。

    【讨论】:

    • 我需要一个匹配组组合的正则表达式 - 例如一组 n 个相同字符,后跟一组 m 个相同字符。更简单的模式如下所示:xxyyyy - 但也可能是 xxayyyy 或 xxaaayyyy - 这样两个组都由任意字符分隔。
    • 已更新。希望我能理解你。
    【解决方案3】:

    嗯,这适用于第一个......

    ((.)(.))(\2\3)+
    

    【讨论】:

    • 你能简单解释一下这个正则表达式吗?
    • 是的。 ((.)(.)) 匹配相邻的 2 个字符(同时看起来也很有暗示性)。 (\2\3) 再次匹配相同的 2 个字符,并且 + 表示这必须发生 1 次或更多次。看看它,你也许可以在第一组中去掉外括号并相应地更改后面的引用。
    • 但是外括号看起来更具暗示性,所以请把它们留在里面。
    • 出于某种原因,外面的括号让我想起了日本的电子游戏。
    【解决方案4】:

    javascript 中的示例

    a = "This is my foobababababaf string"
    
    console.log(a.replace(/(.)(.)(\1\2)+/, "<<$&>>"))
    
    a = "This is my foobaafoobaaaooo string"
    
    console.log(a.replace(/(.)\1+(.)\2+/, "<<$&>>"))
    

    【讨论】:

    • 这两个正则表达式都可以匹配单个字符的运行,例如aaaaaa;我不认为 OP 想要那样。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-03-18
    • 1970-01-01
    • 2021-11-03
    • 1970-01-01
    • 1970-01-01
    • 2020-07-04
    相关资源
    最近更新 更多