【问题标题】:How to recognize tokens between repeated delimiters?如何识别重复分隔符之间的标记?
【发布时间】:2019-01-28 04:54:03
【问题描述】:

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

示例输入:

你好,@name@!请联系 admin@example.com,亲爱的@name@!

期望的输出:

你好,彼得!亲爱的彼得,请联系 admin@example.com!

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

$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,因为@ 之前已经用过了。输出是:

你好,彼得!请联系 admin@example.com,亲爱的@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);

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

你好,@彼得@!请联系 admin@example.com,亲爱的@Peter@!

如何将一对@s 之间的任何内容传递给回调,并将其替换为@s?

令牌将不包含换行符或@

另一个例子

这有点人为,但显示我想要做什么,因为当前的建议依赖于单词边界。

输入

狗@猫@驴@斑马

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

【问题讨论】:

  • 如果你知道变量名,那么用字符串替换@name@而不是寻找任何@...@不是更容易吗?
  • 而不是过于宽泛的.* 匹配\w+。并在此之前使用回顾来断言没有字母。
  • @Devon 在实际代码中我运行数据库查询以查找是否已定义令牌。
  • @Džuris 请检查ideone.com/AYTjmk,如果您需要,我会发布。
  • 好吧,如果你真的想匹配@之间的任何字符,它也可能是ideone.com/Lm19Gc

标签: php regex preg-replace-callback


【解决方案1】:

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

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

【讨论】:

  • 这很不错,但如果可能的话,我想避免强制性的单词边界。回调应该只接收任何连续的@s 之间的任何内容。
【解决方案2】:

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

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

【讨论】:

    猜你喜欢
    • 2022-01-16
    • 2015-10-17
    • 1970-01-01
    • 2017-09-21
    • 1970-01-01
    • 2019-09-14
    • 2013-05-10
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多