regex 如何将一个字符串列表编译成一个紧凑的正则表达式?

cl25kdpy  于 2023-03-13  发布在  其他
关注(0)|答案(1)|浏览(71)

我将从一个例子开始,因为我不确定我是否能恰当地解释它。
这个问题比较容易的部分(我想虽然我也不明白):

  • 取一些字符串,例如“Example”、“DOMNode”、“DOMext”、“DOMElement”
  • 和输出“(示例|DOM(节点|正文|元素))'

问题的更复杂部分是从字符串的两端进行匹配

  • 取一些字符串,例如“示例”、“数组迭代器”、“递归数组迭代器"、”目录迭代器“、”递归目录迭代器“
  • 和输出“(示例|(递归)?(数组|目录)迭代器)'
  • 我有一个字符串(模式)列表来匹配主题。
  • 我可以简单地将模式与交替(这是我当前的系统)连接起来,但是我想找到一种方法将公共前缀分组到交替组中。

这并不是一个真正的优化,但我一直试图做它作为一个有趣的练习,现在它只是给我一个头痛哈哈。
我试着把每个字符串按字母拆开,匹配每一种可能的组合。
我记不起我在上午做过的所有事情了。我在拼命工作。
我找不到一种方法来获得共同的前缀或存储他们,所以我可以重建他们到一个正则表达式。似乎是一个简单的问题,但我卡住了。
我有一个用下划线分隔字符串的函数:(当你知道如何用下划线分隔前缀时效果很好)

<?php
/**
 * separates snake case names into nested hierarchies.
 */
function processArray(array $funcs): array
 {
    $loop = false;
    $current = false;
    $newFuncs = [];
    foreach ($funcs as $name)
     {
        $pos = strpos($name, '_');
        if ($current and !str_starts_with($name, $current))
         {
            if ($loop || $pos)
             {
                $newFuncs[$current] = processArray($newFuncs[$current]);
                $loop = false;
             }
            $current = false;
         }
        if ($pos)
         {
            $current = substr($name, 0, $pos + 1);
            $newFuncs[$current] ??= [];
            $subName = substr($name, $pos + 1);
            $newFuncs[$current][] = $subName;
            if (strpos($subName, '_'))
             {
                $loop = true;
             }
         }
        else
         {
            if ($loop)
             {
                $newFuncs[$current] = processArray($newFuncs[$current]);
                $loop = false;
             }
            $current = false;
            $newFuncs[] = $name;
         }
     }
    return $newFuncs;
 }

function getRegex(array $strs): string
 {
    static $level = 0;
    $ret = '(';
    foreach ($strs as $key => $value)
     {
        if (is_array($value))
         {
            $strs[$key] = (is_string($key)?$key:'').getRegex($value);
         }
     }
    $ret.= implode('|', $strs);
    $ret.= ')';
    return $ret;
 }

$funcs = get_defined_functions()['internal'];
sort($funcs);

$funcs = processArray($funcs);
$getRegex = getRegex($funcs);

//remove isolated groups (groups with only one alternation)
do
 {
    $getRegex = preg_replace('~\(([a-zA-Z_0-9]+?)\)~', '$1', $getRegex, -1, $count);
 } 
while ($count);

var_dump($getRegex);
guykilcj

guykilcj1#

创建一个完整的正则表达式trie是一个相当复杂的动作。
而且它绝对减少了匹配的时间。
我用一个软件程序做了这个。
只需将字符串放入一个字段,它就会进行解析,然后输出一个trie。
你的样本很容易手工完成,但我不希望那些算法
有利于节目的投放。
当你构造一个trie时,如果可能的话,一定要使用降序方法。

示例、域节点、域文本、域元素

降序(推荐)Example|DOM(?:(?:Tex|Elemen)t|Node)
升序(不推荐)DOM(?:(?:Elemen|Tex)t|Node)|Example

示例,数组迭代器,递归数组迭代器,目录迭代器,递归目录迭代器

降序(推荐)(?:Recursive(?:Director|Arra)|Director|Arra)yIterator|Example
升序(不推荐)(?:Arra|Director|Recursive(?:Arra|Director))yIterator|Example

相关问题