首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >如何从上到下匹配正则表达式

如何从上到下匹配正则表达式
EN

Stack Overflow用户
提问于 2017-05-24 13:56:54
回答 1查看 447关注 0票数 1

出于学习的原因,我尝试创建一个PHP模板引擎。

假设我们有以下数组

代码语言:javascript
运行
复制
$regexList = [
  'varPattern' => '/{{\s*\$(.*?)\s*}}/',
  'loopPattern' => '/@for\((.*?)\)\s*{{((?:[^{}]|(?R))*)}}/',
  'statementPattern' => '/@if\((.*?)\)\s*{{((?:[^{}]|(?R))*)}}/'
]

以及以下功能

代码语言:javascript
运行
复制
getVar($varName);
loop($arrayName);
getStatementResult($booleanExpression);

这根弦叫着:

代码语言:javascript
运行
复制
$string = '

<span>{{ $fullName }}</span>

@for($names as $name)
{{
  @if($name == 'Eleandro)
  {{
    <p>{{ $name }}</p>
  }}
}} ';

其思想是从上到下读取字符串,并依赖正则表达式列表,找到结果并将其交给正确的函数。

例如:要查找的第一件事必须是{{$string}},因此我们将变量名传递给getVar($matchedVarName)函数。

接下来必须是@loop(){{ }},所以,我们称之为loop($matchedArrayName);

在循环中必须找到@if(){{ }},因此,我们得到结果并给出匹配值的getStatementResult($matchedBooleanExpression)

我怎样才能按照正确的顺序(从上到下)做这件事?谢谢。

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2017-05-24 14:53:26

如果您将PREG_OFFSET_CAPTURE标志用于preg_match_all,则这是可能的。该标志将做的是,更改捕获的匹配,以将偏移量包含在模式字符串中。现在,我们需要做的唯一一件事就是按照所有匹配的偏移量要求,按照相同的顺序遍历所有的比赛。

这有点棘手,但绝对有可能。我的做法如下:

  1. 创建每个正则表达式匹配的数组。由于您有三个正则表达式,这将是一个具有三个值的数组。每个值都是与该正则表达式的$matches匹配的preg_match_all。 重要注意事项:匹配是根据每个数组中的偏移量排序的。
  2. 为每个正则表达式创建一个索引数组。我们将使用它来跟踪每个正则表达式的位置。这被初始化为[0, 0, 0]。为了使它更通用,并让它处理任意数量的正则表达式,我使用了array_fill
  3. 虽然并不是所有的火柴都被处理了..。
代码语言:javascript
运行
复制
1. Determine the next match to handle. This will be the regular expression of which the next match has the minimum offset. I wrote a small `minIndex` function for this.
2. Call the appropriate function (hardcoded in `$functions` below) with the value of the matched group. At this point, we know which function to call because we know which regular expression created this particular match.

如果您能够对所有匹配调用相同的函数,我们就可以将所有匹配合并到一个数组中,并按偏移量对它们进行排序。

3.增加匹配正则表达式的索引。

在这一点上,我应该指出,示例中的最后两个正则表达式根本不匹配。这是因为在循环和语句中有{}的实例。为了演示起见,我只是切断了这些正则表达式的一部分,因此它们只匹配循环/语句的条件。

下面的脚本将打印这个。

代码语言:javascript
运行
复制
getVar('fullName')
loop('$names as $name')
getStatementResult('$name === "Eleandro"')
getVar('name')

我相信,这就是你所期望的结果。

代码语言:javascript
运行
复制
// functions
function getVar($varName) {
    echo "getVar('$varName')\n";
}

function loop($arrayName) {
    echo "loop('$arrayName')\n";
}

function getStatementResult($booleanExpression) {
    echo "getStatementResult('$booleanExpression')\n";
}

// input
$string = '

<span>{{ $fullName }}</span>

@for($names as $name)
{{
  @if($name === "Eleandro")
  {{
    <p>{{ $name }}</p>
  }}
}} ';

// helper functions
function minIndex($arr) {
    $i = 0; $l = count($arr);
    $min = false; $minI = -1;
    for ($i = 0; $i < $l; ++$i) {
        if ($arr[$i] === false)  continue; // skip non numbers
        if ($min === false || $arr[$i] < $min) {
            $min = $arr[$i];
            $minI = $i;
        }
    }
    return $minI;
}

// regular expressions
$regexList = [
    'varPattern' => '/{{\s*\$(.*?)\s*}}/',
    'loopPattern' => '/@for\((.*?)\)\s*{{/',
    'statementPattern' => '/@if\((.*?)\)\s*{{/'
];

// functions to map above regexes to
$functions = ['getVar', 'loop', 'getStatementResult'];
// matches per regex
$matchesAll = [];

// combine the above regexes into a single one, run that
foreach ($regexList as $name => $regex) {
    unset($matches);
    preg_match_all($regex, $string, $matches, PREG_OFFSET_CAPTURE);
    $matchesAll[] = $matches;
}

// walk over the matches in order of offset in string
// current match per regex
$indexes = array_fill(0, count($regexList), 0);
// number of matches per regex
$counts = array_map(function($m) { return count($m[0]); }, $matchesAll);
while ($indexes !== $counts) {
    $offsets = array_map(function($m, $i) {
            return (count($m[0]) > $i ? $m[0][$i][1] : false);
        }, $matchesAll, $indexes);
    $next = minIndex($offsets);
    call_user_func($functions[$next],
        $matchesAll[$next][1][$indexes[$next]][0]);
    $indexes[$next]++;
}
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/44160551

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档