【问题标题】:How to wrap words or words sequences which have not been already wrapped?如何包装尚未包装的单词或单词序列?
【发布时间】:2011-04-24 20:18:23
【问题描述】:

我正在尝试使用 preg_replace 将给定列表中的单词和单词序列包装起来。它几乎可以工作,但在某些用例中它不起作用,我不知道它是如何工作的。

例如我这样做:

    // sort by descending length
    usort($this->_keywords, function($a,$b){return(strlen($a)<strlen($b));});

    // wrapper is -%string%-
    foreach ($this->_keywords as $keyword) {
        $value = preg_replace('/((?!-)' . $keyword . '(?!-))/i', str_replace('%string%', '\1', $this->_wrapper), $value);
    }

来自这个关键字列表:

  • 洛雷姆
  • ipsum
  • 坐在一起
  • sed
  • sed enim

我想要结果:

-Lorem- -ipsum- dolor -sit amet-, consectetur adipiscing 精英。菜豆 rhoncus venenatis orci sed porta。赛德 非多洛厄洛斯。暂停马萨 -sit amet- nulla egestas facilisis。克拉斯 fringilla, leo ac ullamcorper semper, urna eros pretium lectus, nec rhoncus ligula risus eu velit。 Nulla eu 大皮布斯麦格纳。 sed vehicula tristique 拉西尼亚。 Maecenas tincidunt metus 在 urna consequat nec congue libero 伊库利斯。 Nulla facilisi。菜豆 -sed- sem ut risus mattis accumsan eu -sed 敌人-。 Pellentesque 居民 morbi tristique senectus et netus et malesuada 名声 ac turpis egestas。 Suspendisse id est velit, eu cursus 夸姆Vivamus lacinia euismod pretium。

有什么想法吗?

【问题讨论】:

  • 您遇到的具体问题是什么?

标签: php regex word text-analysis


【解决方案1】:

最简单的方法是使用preg_replace_callback(),并匹配已经包装好的单词,以及每个关键字。当匹配是一个已被包装的单词时,只需将其原封不动地返回即可。无需进行有问题的环视。

function compare_length($a, $b) {
    return strlen($a) < strlen($b);
}

function build_regex($keywords) {
    usort($keywords, 'compare_length');
    $pieces []= '/(?<wrapped>-[\w\s]*-)|(?<keyword>';
    for ($i = 0; $i < count($pieces); $i++) {
        if ($i > 0) $pieces []= '|';
        $pieces []= preg_quote($keywords[$i], '/');
    }
    $pieces []= ')/';
    return implode("", $pieces);
}

function wrap_callback($match) {
    if (!empty($match['wrapped'])) {
        return $match['wrapped'];
    }
    return "-{$match['wrapped']}-";
}

function wrap($text, $keywords) {
    $regex = build_regex($keywords);
    return preg_replace_callback($regex, 'wrap_callback');
}

【讨论】:

    【解决方案2】:

    我终于通过使用对应于单词边界的\b 元字符解决了我的问题。

    public function filter($value)
    {
        usort($this->_keywords, function($a,$b){return(strlen($a)<strlen($b));});
    
        foreach ($this->_keywords as $keyword) {
            $value = preg_replace(
                '/((?<!-)('.$keyword.'\b)(?!\-))/i',
                str_replace('%string%', '\2', $this->_wrapper) . '\3',
                $value
            );
        }
    
        return $value;
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-01-29
      相关资源
      最近更新 更多