如何识别重复分隔符之间的标记?

How to recognize tokens between repeated delimiters?

我正在尝试解析两侧由 @ 分隔标记的模板。

示例输入:

Hello, @name@! Please contact admin@example.com, dear @name@!

期望的输出:

Hello, Peter! Please contact admin@example.com, dear Peter!

寻找匹配项并替换的天真的尝试:

$content = 'Hello, @name@! Please contact admin@example.com, dear @name@!';

preg_replace_callback(
    '/(@.*@)/U', function ($token) {
        if ('@name@' == $token)  //replace recognized tokens with values
            return 'Peter';

        return $token;  //ignore the rest
    }, $content);

此正则表达式无法正确处理备用 @ - 它匹配第一个 @name@@example.com, dear @ 而无法匹配第二个 @name,因为 @ 之前已经用完了。输出为:

Hello, Peter! Please contact admin@example.com, dear @name@!

为了避免支出 @,我尝试使用环顾四周:

$content = 'Hello, @name@! Please contact admin@example.com, dear @name@!';

preg_replace_callback(
    '/(?<=@)(.*)(?=@)/U', function ($token) {
        if ('name' == $token)  //replace recognized tokens with values
            return 'Peter';

        return $token;  //ignore the rest
    }, $content);

这正确匹配了一对 @ 之间包含的每个子字符串,但它不允许我自己替换分隔符。输出为:

Hello, @Peter@! Please contact admin@example.com, dear @Peter@!

如何将一对 @ 之间的任何内容传递给回调并替换它以替换 @

令牌将不包括换行符或 @

另一个例子

这有点做作,但为了展示我想做的事情,因为当前的建议依赖于单词边界。

输入

Dog@Cat@Donkey@Zebra

我希望回调获取 Cat 以查看 @Cat@ 是否应替换为令牌值,然后接收 Donkey 以查看 @Donkey@ 是否应为已替换。

我建议使用:/@\b([^@]+)\b@/

Capture group0 holds:  @name@
Capture group1 holds:  name

由于分隔符可能重叠,我不确定这是否可以使用正则表达式来完成。但是这里有一个递归函数可以完成这项工作。此代码不关心令牌的外观(即它不必是字母数字),只要它出现在 @ 个符号之间即可:

function replace_tokens($tokens, $string) {
    $parts = explode('@', $string, 3);
    if (count($parts) < 3) {
        // none or only one '@' so can't be any tokens to replace
        return implode('@', $parts);
    }
    elseif (in_array($parts[1], array_keys($tokens))) {
        // matching token, replace
        return $parts[0] . $tokens[$parts[1]] . replace_tokens($tokens, $parts[2]);
    }
    else {
        // not a matching token, try further along...
        // need to replace the `@` symbols that were removed by explode
        return $parts[0] . '@' . $parts[1] . replace_tokens($tokens, '@' . $parts[2]);
    }
}

$tokens = array('name' => 'John', 'Cat' => 'Goldfish', 'xy zw' => '45');
echo replace_tokens($tokens, "Hello, @name@! Please contact admin@example.com, dear @name@!") . "\n";
echo replace_tokens($tokens, "Dog@Cat@Donkey@Zebra") . "\n";
echo replace_tokens($tokens, "auhdg@xy zw@axy@Cat@") . "\n";
$tokens = array('Donkey' => 'Goldfish');
echo replace_tokens($tokens, "Dog@Cat@Donkey@Zebra") . "\n";

输出:

Hello, John! Please contact admin@example.com, dear John!
DogGoldfishDonkey@Zebra
auhdg45axyGoldfish
Dog@CatGoldfishZebra