当前位置: 首页 > 知识库问答 >
问题:

在PHP中为regex模式生成所有可能的匹配项

别烨熠
2023-03-14

SO上有很多关于如何解析正则表达式模式并输出该模式所有可能匹配的问题。然而,出于某种原因,我能找到的每一个问题(1, 2, 3, 4, 5, 6, 7,可能更多)要么是针对Java,要么是针对各种C(只有一个针对JavaScript),我目前需要在PHP中完成这项工作。

我已经在Google上搜索到了我最喜欢的内容,但无论我做什么,Google给我的唯一东西就是指向preg\u match()的文档链接,以及关于如何使用regex的页面,这与我在这里想要的正好相反。

我的正则表达式模式都非常简单,保证是有限的;使用的唯一语法是:

  • 字符类

因此,一个例子可能是hun(k | der)(s | ed | ing) 匹配动词chunk、thunk、chunder和thunder的所有可能形式,共16种排列。

理想情况下,应该有一个PHP库或工具,它可以迭代(有限的)正则表达式模式,并输出所有可能的匹配项,一切都准备就绪。有人知道这样的库/工具是否已经存在吗?

如果不是,那么什么是优化的方法?JavaScript的这个答案是我所能找到的最接近于我应该能够适应的东西,但不幸的是,我无法理解它的实际工作方式,这使得适应变得更加棘手。另外,无论如何,在PHP中可能有更好的方法。对于如何最好地分解任务的一些逻辑指针,我们将不胜感激。

编辑:由于显然不清楚这在实践中会是什么样子,我正在寻找允许这种类型输入的东西:

$possibleMatches = parseRegexPattern('[ct]hun(k|der)(s|ed|ing)?');

–然后打印$possibleMatches应该会得到这样的结果(在我的情况下,元素的顺序并不重要):

Array
(
    [0] => chunk
    [1] => thunk
    [2] => chunks
    [3] => thunks
    [4] => chunked
    [5] => thunked
    [6] => chunking
    [7] => thunking
    [8] => chunder
    [9] => thunder
    [10] => chunders
    [11] => thunders
    [12] => chundered
    [13] => thundered
    [14] => chundering
    [15] => thundering
)

共有1个答案

林建本
2023-03-14

>

  • 您需要去掉可变模式;您可以使用preg\u match\u all来执行此操作

    preg_match_all("/(\[\w+\]|\([\w|]+\))/", '[ct]hun(k|der)(s|ed|ing)?', $matches);
    
    /* Regex:
    
    /(\[\w+\]|\([\w|]+\))/
    /                       : Pattern delimiter
     (                      : Start of capture group
      \[\w+\]               : Character class pattern
             |              : OR operator
              \([\w|]+\)    : Capture group pattern
                        )   : End of capture group
                         /  : Pattern delimiter
    
    */
    

    然后可以将捕获组扩展为字母或单词(取决于类型)

    $array = str_split($cleanString, 1); // For a character class
    $array = explode("|", $cleanString); // For a capture group
    

    递归地遍历每个$数组

    function printMatches($pattern, $array, $matchPattern)
    {
        $currentArray = array_shift($array);
    
        foreach ($currentArray as $option) {
            $patternModified = preg_replace($matchPattern, $option, $pattern, 1);
            if (!count($array)) {
                echo $patternModified, PHP_EOL;
            } else {
                printMatches($patternModified, $array, $matchPattern);
            }
        }
    }
    
    function prepOptions($matches)
    {
        foreach ($matches as $match) {
            $cleanString = preg_replace("/[\[\]\(\)\?]/", "", $match);
            
            if ($match[0] === "[") {
                $array = str_split($cleanString, 1);
            } elseif ($match[0] === "(") {
                $array = explode("|", $cleanString);
            }
            if ($match[-1] === "?") {
                $array[] = "";
            }
            $possibilites[] = $array;
        }
        return $possibilites;
    }
    
    $regex        = '[ct]hun(k|der)(s|ed|ing)?';
    $matchPattern = "/(\[\w+\]|\([\w|]+\))\??/";
    
    preg_match_all($matchPattern, $regex, $matches);
    
    printMatches(
        $regex,
        prepOptions($matches[0]),
        $matchPattern
    );
    

    在使用中,你会把它放在“preg_match_all”之前。

    $regex        = 'This happen(s|ed) to (be(come)?|hav(e|ing)) test case 1?';
    
    echo preg_replace_callback("/(\(|\|)(\w+)(?:\(([\w\|]+)\)\??)/", function($array){
        $output = explode("|", $array[3]);
        if ($array[0][-1] === "?") {
            $output[] = "";
        }
        foreach ($output as &$option) {
            $option = $array[2] . $option;
        }
        return $array[1] . implode("|", $output);
    }, $regex), PHP_EOL;
    

    输出:

    This happen(s|ed) to (become|be|have|having) test case 1?
    

    主要是更新正则表达式:

    $matchPattern = "/(?:(\[\w+\]|\([\w|]+\))\??|(\w\?))/";
    

    并将一个else添加到preptions函数中:

    } else {
        $array = [$cleanString];
    }
    
    function printMatches($pattern, $array, $matchPattern)
    {
        $currentArray = array_shift($array);
    
        foreach ($currentArray as $option) {
            $patternModified = preg_replace($matchPattern, $option, $pattern, 1);
            if (!count($array)) {
                echo $patternModified, PHP_EOL;
            } else {
                printMatches($patternModified, $array, $matchPattern);
            }
        }
    }
    
    function prepOptions($matches)
    {
        foreach ($matches as $match) {
            $cleanString = preg_replace("/[\[\]\(\)\?]/", "", $match);
            
            if ($match[0] === "[") {
                $array = str_split($cleanString, 1);
            } elseif ($match[0] === "(") {
                $array = explode("|", $cleanString);
            } else {
                $array = [$cleanString];
            }
            if ($match[-1] === "?") {
                $array[] = "";
            }
            $possibilites[] = $array;
        }
        return $possibilites;
    }
    
    $regex        = 'This happen(s|ed) to (be(come)?|hav(e|ing)) test case 1?';
    $matchPattern = "/(?:(\[\w+\]|\([\w|]+\))\??|(\w\?))/";
    
    $regex = preg_replace_callback("/(\(|\|)(\w+)(?:\(([\w\|]+)\)\??)/", function($array){
        $output = explode("|", $array[3]);
        if ($array[0][-1] === "?") {
            $output[] = "";
        }
        foreach ($output as &$option) {
            $option = $array[2] . $option;
        }
        return $array[1] . implode("|", $output);
    }, $regex);
    
    
    preg_match_all($matchPattern, $regex, $matches);
    
    printMatches(
        $regex,
        prepOptions($matches[0]),
        $matchPattern
    );
    

    输出:

    This happens to become test case 1
    This happens to become test case 
    This happens to be test case 1
    This happens to be test case 
    This happens to have test case 1
    This happens to have test case 
    This happens to having test case 1
    This happens to having test case 
    This happened to become test case 1
    This happened to become test case 
    This happened to be test case 1
    This happened to be test case 
    This happened to have test case 1
    This happened to have test case 
    This happened to having test case 1
    This happened to having test case 
    

  •  类似资料:
    • 我正在尝试使用 php 正则表达式解析文本。我写了一个模式匹配,所有东西都符合要求。我不想要它。它必须在同一行上单独匹配目标。 模式: 目标数据字符串: 带有PREG_SET_ORDER标志的结果preg_match_all: 如果目标数据被放置在单独的行和相同的正则表达式模式执行结果;(我想要这些结果,但没有新行) 谢谢你的帮助。

    • 或者更好的方法是遍历它,为参数的每个索引获取TRUE或FALSE标志 我只知道如何使用matcher.find()进行循环,如果有任何帮助,我将不胜感激

    • 我想知道为什么这个regex组在Java中不适合我?它在寻找组匹配时抛出异常。我正试着把用破折号隔开的数字匹配起来。

    • 问题内容: 我认为我遇到了一个听起来比实际容易的问题……我不太确定。我想定义一个正则表达式,并且要构建一些与之匹配的字符串。 我可以导入具有该功能的任何模块吗?最好不要使用或暴力破解方法。必须有一种更优雅的方法来做到这一点。 问题答案: 我一直在研究一个小的帮助程序库,用于使用Python生成随机字符串 它包含一个方法,该方法允许您从正则表达式创建字符串: 目前,它适用于大多数基本正则表达式。

    • 问题内容: 从那时起,我一直在TutorialsPoint上查看代码,此后一直困扰着我……看一下这段代码: 此代码成功打印: 但是根据正则表达式,为什么它不返回其他可能的结果,例如: 要么 如果此代码不适合这样做,那么我该如何编写一个可以找到所有可能匹配项的代码? 问题答案: 这是因为的贪婪,随之而来的是回溯。 字串: 正则表达式: 我们都知道那是贪婪的,并且尽可能匹配所有字符。因此,第一个匹配所

    • 模式出现在 Rust 的很多地方。你已经在不经意间使用了很多模式!本部分是一个所有有效模式位置的参考。 如第六章所讨论的,一个模式常用的位置是 match 表达式的分支。在形式上 match 表达式由 match 关键字、用于匹配的值和一个或多个分支构成,这些分支包含一个模式和在值匹配分支的模式时运行的表达式: match 表达式必须是 穷尽(exhaustive)的,意为 match 表达式所有