Php 我怎样才能只匹配发生的第一行?

Php 我怎样才能只匹配发生的第一行?,php,regex,Php,Regex,我有这个字符串: $str = "11ff11 22mm22 33gg33 mm22mm vv55vv 77ll77 55kk55 kk22kk bb11bb"; 有两种模式: {两个数字}{两个字母}{两个数字} {两个字母}{两个数字}{两个字母} 当模式改变时,我试图匹配第一行。所以我想匹配这些: 11ff11 -- this 22mm22 33gg33 mm

我有这个字符串:

$str = "11ff11
        22mm22
        33gg33
        mm22mm
        vv55vv
        77ll77
        55kk55
        kk22kk
        bb11bb";
有两种模式:

  • {两个数字}{两个字母}{两个数字}
  • {两个字母}{两个数字}{两个字母}
  • 当模式改变时,我试图匹配第一行。所以我想匹配这些:

    11ff11  -- this
    22mm22
    33gg33
    mm22mm  -- this
    vv55vv
    77ll77  -- this
    55kk55
    kk22kk  -- this
    bb11bb
    
    这是我的:


    但它匹配所有的线条。。!如何将其限制为仅匹配同一模式的第一行?

    不确定是否可以仅使用一个表达式执行此操作,但您可以迭代字符串并在更改时进行测试:

    <?php
    
    $str = "11ff11
            22mm22
            33gg33
            mm22mm
            vv55vv
            77ll77
            55kk55
            kk22kk
            bb11bb";
    
    $exploded = explode(PHP_EOL, $str);
    $patternA = '/(\d{2}[a-z]{2}\d{2})/';
    $patternB = '/([a-z]{2}\d{2}[a-z]{2})/';
    
    $result = [];
    $currentPattern = '';
    
    //get first and check what pattern is
    if(preg_match($patternA, $exploded[0])){
        $currentPattern = $patternA;
        $result[] = $exploded[0];
    } elseif(preg_match($patternB, $exploded[0])){
        $currentPattern = $patternB;
        $result[] = $exploded[0];
    } else {
        //.. no pattern on first element, should we continue?
    }
    
    //toggle
    $currentPattern = $currentPattern == $patternA ? $patternB : $patternA;
    
    foreach($exploded as $e) {
        if(preg_match($currentPattern, $e)) {
            //toggle
            $currentPattern = $currentPattern == $patternA ? $patternB : $patternA;
            $result[] = trim($e);
        }
    }
    echo "<pre>";
    var_dump($result);
    echo "</pre>";
    

    由于空间问题,我无法使用lookaround。但使用经典正则表达式,它是可用的。它找到重复模式的序列,只捕获第一个

    (?:(\d)\s+)(?:\d\s+)*|(?:(a)\s+)(?:a\s+)*
    

    为了了解它是如何工作的,我用数字和字母的模式制作了一个简单的示例:

    /^.*|(?<=[a-z]{2}\n)\d{2}[a-z]{2}\d{2}|(?<=\d{2}\n)[a-z]{2}\d{2}[a-z]{2}/
    

    这是我的看法。我以前从未使用过lookbehinds,我的正则表达式技能也不太好,但这似乎能回报你想要的


    /^.*.|(?您需要lookarounds。如前所述,您正在匹配每一行,因为您被指定为允许两种类型的行的每一行匹配。另一个基于lookaround的想法:@stack您看过演示吗?很高兴提供帮助!祝您好运!@splash58最好将“\s+”替换为“\s*”,因为其中一个匹配可能是列表中的最后一行(结尾没有新行)。@splash58您的解决方案就像一个符咒。这是最好的答案。只删除开头的非捕获组。没有它们的结果将是相同的:
    (\d{2}[a-z]{2}\d{2})\s*(?:\d{2}[a-z]{2}\d{2}\s*)*([a-z]{2}\d{2}[a-z]{s*(\a-z]{2}[a-z]{2}]*
    @elchininet是的,你是对的。我这样做是为了统一。不要认为这会降低效率:)好的解决方案@georaldc。只将捕获组添加到匹配中。问候;)
    (?:(\d{2}[a-z]{2}\d{2})\s+)(?:\d{2}[a-z]{2}\d{2}\s+)*|(?:([a-z]{2}\d{2}[a-z]{2})\s+)(?:[a-z]{2}\d{2}[a-z]{2}\s+)*
    
    (?:(\d)\s+)(?:\d\s+)*|(?:(a)\s+)(?:a\s+)*
    
    /^.*|(?<=[a-z]{2}\n)\d{2}[a-z]{2}\d{2}|(?<=\d{2}\n)[a-z]{2}\d{2}[a-z]{2}/