【问题标题】:Replace (add) words case sensitive from arrays从数组中替换(添加)区分大小写的单词
【发布时间】:2017-02-24 17:20:52
【问题描述】:

我是 php 新手,尤其是正则表达式。 我的目标是使用数组中列出的“关键字”提示自动丰富文本。

到目前为止,我已经来了。

$pattern = array("/\bexplanations\b/i",
            "/\btarget\b/i", 
            "/\bhints\b/i",
            "/\bhint\b/i",
);

$replacement = array("explanations <i>(Erklärungen)</i>",
            "target <i>Ziel</i>", 
            "hints <i>Hinsweise</i>",
            "hint <i>Hinweis</i>",
);

$string = "Target is to add some explanations (hints) from an array to 
this text. I am thankful for every hint.";

echo preg_replace($pattern, $replacement, $string);

返回:

target <i>Ziel</i> is to add some explanations <i>(Erklärungen)</i> (hints <i>Hinsweise</i>) from an array to this text. I am thankful for every hint <i>Hinweis</i>

1) 一般来说,我想知道是否有更优雅的解决方案(最终不替换原词)? 在以后的状态下,数组将包含超过 1000 个项目......并且来自 mariadb。

2) 我怎样才能实现“目标”一词实现区分大小写的处理? (不重复我的数组的长度)。

抱歉我的英语不好,非常感谢。

【问题讨论】:

  • 在正则表达式模式中用括号将搜索词括起来,并在替换中使用反向引用。

标签: php arrays regex


【解决方案1】:

如果您打算增加数组的大小并且文本可能有点长,则处理所有文本(每个单词一次)不是一种可靠的方法。而且,数组很大,用所有的单词构建一个巨大的交替也不可靠。 但是,如果您将所有翻译存储在一个关联数组中并在单词边界上拆分文本,您可以一次性完成:

// Translation array with all keys lowercase
$trans = [ 'explanations' => 'Erklärungen',
           'target' => 'Ziel',
           'hints' => 'Hinsweise',
           'hint' => 'Hinweis'
];

$parts = preg_split('~\b~', $text);

$partsLength = count($parts);

// All words are in the odd indexes
for ($i=1; $i<$partsLength; $i+=2) {
    $lcWord = strtolower($parts[$i]);

    if (isset($trans[$lcWord]))
        $parts[$i] .= ' <i>(' . $trans[$lcWord] . ')</i>';
}

$result = implode('', $parts);

实际上这里的限制是您不能使用包含单词边界的键(例如,如果您想用几个单词翻译整个表达式),但是如果您想处理这种情况,您可以使用preg_match_all 代替 preg_split 并构建一个测试这些特殊情况的模式,例如:

preg_match_all('~mushroom pie\b|\w+|\W*~iS', $text, $m);

$parts = &$m[0];
$partsLength = count($parts);

$i = 1 ^ preg_match('~^\w~', $parts[0]);

for (; $i<$partsLength; $i+=2) {

...

(如果你有很多例外(太多),其他策略也是可能的。)

【讨论】:

  • 非常感谢。作为菜鸟,我需要几个小时才能逐行浏览。在出于学习目的进行测试之后,我仍然想知道它的稳定性如何,特别是如果我使用带有双空格等的 Input。虽然我目前的技能还不够复杂,无法完全解决性能问题,但我的进一步研究变成了一个更具体的方向。
  • @FriedrichSiever:性能问题很简单,将preg_replace(或str_replace)与模式数组一起使用涉及隐式循环,主题字符串完全针对数组中的每一项进行处理(简而言之,如果您有 1000 个单词,则该字符串将被解析 1000 次,并且每次替换后该字符串都会增长)。如果您使用我的解决方案,该字符串仅被解析一次以构建部件数组,那么如果替换数组中有一个键,您只需测试一半的部件(单词)(像这样构建替换数组,避免使用in_array)
  • @FriedrichSiever: 其他问题,考虑文本:"a child is playing." 和数组['child' =&gt; 'Kind', 'kind' =&gt; 'Art'],用preg_replacestr_replace 方法,你得到:"a child &lt;i&gt;(Kind &lt;i&gt;(Art)&lt;/i&gt;)&lt;/i&gt; is playing."。我希望你没有带有"fat"这个词的文字。
  • 再次感谢您的友好和宝贵的解释和例子。它们对我很有启发性。
【解决方案2】:

在正则表达式模式中用括号将搜索词括起来,并在替换中使用反向引用。

看到这个PHP demo

$pattern = array("/\b(explanations)\b/i", "/\b(target)\b/i", "/\b(hints)\b/i", "/\b(hint)\b/i", ); 
$replacement = array('$1 <i>(Erklärungen)</i>', '$1 <i>Ziel</i>', '$1 <i>Hinsweise</i>', '$1 <i>Hinweis</i>', ); 
$string = "Target is to add some explanations (hints) from an array to this text. I am thankful for every hint."; 
echo preg_replace($pattern, $replacement, $string);

这样,您将使用文本中使用的实际大小写替换找到的单词。

请注意,确保模式按降序排列非常重要,较长的模式在较短的模式之前(首先是Targets,然后是Target,等等)

【讨论】:

  • 哇。太感谢了。这恰好解决了我的问题,并为我在该学科领域的进一步研究和研究提供了正确的方向。虽然 Regex 似乎很难学,但它们确实很强大。再次感谢您的演示。
  • 终于完成了。关于我在这里的 NewB 状态,在你回答的时候我是不允许的...... .
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2016-10-29
  • 1970-01-01
  • 2020-02-08
  • 1970-01-01
  • 1970-01-01
  • 2010-10-29
  • 2021-03-29
相关资源
最近更新 更多