正则表达式仅匹配单个单词
Regex matches on single words only
我得到了以下函数,其中包含一个正则表达式
public function searchDOM( $content, $search, $replace, $excludedParents = [] )
{
$dom = HtmlDomParser::str_get_html(
$content,
true,
true,
DEFAULT_TARGET_CHARSET,
false,
DEFAULT_BR_TEXT,
DEFAULT_SPAN_TEXT
);
foreach ( $dom->find( 'text' ) as $element ) {
if ( !in_array( $element->parent()->tag, $excludedParents ) )
$element->innertext = preg_replace(
'/\b' . preg_quote( $search, "/" ) . '\b/i',
$replace,
$element->innertext
);
}
我正在将 $search
传递给函数,如下所示:
foreach ( $searcharray as $search ) {
$text = $search[ 'text' ];
$url = $search[ 'url' ];
$replace = "<a href='$url'>$0</a>";
$content = $this->searchDOM(
$content,
$text,
$replace,
[ 'a', 'img', 'script', 'style', 'code', 'pre' ]
);
}
效果很好。但是如果搜索字符串包含 +
例如检测失败。
我该如何解决?
由于您的搜索短语可能包含非单词字符,您应该考虑将它们传递给您的函数,从最长的一个开始,按降序排列。首先,传递 hello world
,然后传递 hello
,然后传递 world
,等等
现在,如果您在搜索短语的开头或结尾有一个非单词字符,/\b\+search\b/i
将不会匹配 I want +search.
中的 +search
,因为没有单词space 和 +
之间的边界(因为两者都是非单词字符)。但是,它会在 I want+search
中找到匹配项,因为 t
和 +
.
之间存在单词边界
使用 lookarounds 断言不是 preceded/followed 的位置,而是用单词 char 代替:
'/(?<!\w)' . preg_quote( $search, "/" ) . '(?!\w)/i'
但可能会出现另一个问题:您已经替换的内容可以再次替换。为避免这种情况,从 text
项目构建一个动态正则表达式,准备一个带有文本 url 的数组,并使用 preg_replace_callback
这是一个示例演示,最终代码可能会因您的输入而有所不同(我没有将其封装到一个函数中,您可以自己轻松完成):
$searches= array();
$searches = array(
array("text" => "hello", "url" => "hello-URL"),
array("text" => "world", "url" => "world-URL"),
array("text" => "hello world", "url" => "helloworld-URL")
);
usort($searches, function($a, $b) {
return strlen($b['text']) - strlen($a['text']);
});
$pat = '~(?<!\w)(?:' . implode("|",
array_map(function($x) { return preg_quote($x['text'], '~'); }, $searches)
) . ')(?!\w)~i';
// echo "$pat\n"; // => ~(?<!\w)(?:hello world|hello|world)(?!\w)~i
$keys = array();
$vals = array();
foreach($searches as $search) {
$keys[] = $search['text'];
$vals[] = $search['url'];
}
$tmparr = array_combine($keys, $vals);
$text = preg_replace_callback($pat, function($m) use ($tmparr) {
return "<a href='" . $tmparr[$m[0]] . "'>" . $m[0] . "</a>"; }, $text);
echo $text;
参见PHP demo。
我得到了以下函数,其中包含一个正则表达式
public function searchDOM( $content, $search, $replace, $excludedParents = [] )
{
$dom = HtmlDomParser::str_get_html(
$content,
true,
true,
DEFAULT_TARGET_CHARSET,
false,
DEFAULT_BR_TEXT,
DEFAULT_SPAN_TEXT
);
foreach ( $dom->find( 'text' ) as $element ) {
if ( !in_array( $element->parent()->tag, $excludedParents ) )
$element->innertext = preg_replace(
'/\b' . preg_quote( $search, "/" ) . '\b/i',
$replace,
$element->innertext
);
}
我正在将 $search
传递给函数,如下所示:
foreach ( $searcharray as $search ) {
$text = $search[ 'text' ];
$url = $search[ 'url' ];
$replace = "<a href='$url'>$0</a>";
$content = $this->searchDOM(
$content,
$text,
$replace,
[ 'a', 'img', 'script', 'style', 'code', 'pre' ]
);
}
效果很好。但是如果搜索字符串包含 +
例如检测失败。
我该如何解决?
由于您的搜索短语可能包含非单词字符,您应该考虑将它们传递给您的函数,从最长的一个开始,按降序排列。首先,传递 hello world
,然后传递 hello
,然后传递 world
,等等
现在,如果您在搜索短语的开头或结尾有一个非单词字符,/\b\+search\b/i
将不会匹配 I want +search.
中的 +search
,因为没有单词space 和 +
之间的边界(因为两者都是非单词字符)。但是,它会在 I want+search
中找到匹配项,因为 t
和 +
.
使用 lookarounds 断言不是 preceded/followed 的位置,而是用单词 char 代替:
'/(?<!\w)' . preg_quote( $search, "/" ) . '(?!\w)/i'
但可能会出现另一个问题:您已经替换的内容可以再次替换。为避免这种情况,从 text
项目构建一个动态正则表达式,准备一个带有文本 url 的数组,并使用 preg_replace_callback
这是一个示例演示,最终代码可能会因您的输入而有所不同(我没有将其封装到一个函数中,您可以自己轻松完成):
$searches= array();
$searches = array(
array("text" => "hello", "url" => "hello-URL"),
array("text" => "world", "url" => "world-URL"),
array("text" => "hello world", "url" => "helloworld-URL")
);
usort($searches, function($a, $b) {
return strlen($b['text']) - strlen($a['text']);
});
$pat = '~(?<!\w)(?:' . implode("|",
array_map(function($x) { return preg_quote($x['text'], '~'); }, $searches)
) . ')(?!\w)~i';
// echo "$pat\n"; // => ~(?<!\w)(?:hello world|hello|world)(?!\w)~i
$keys = array();
$vals = array();
foreach($searches as $search) {
$keys[] = $search['text'];
$vals[] = $search['url'];
}
$tmparr = array_combine($keys, $vals);
$text = preg_replace_callback($pat, function($m) use ($tmparr) {
return "<a href='" . $tmparr[$m[0]] . "'>" . $m[0] . "</a>"; }, $text);
echo $text;
参见PHP demo。