gpt4 book ai didi

php - 在 HTML 中搜索 2 个短语(忽略所有标签)并删除其他所有内容

转载 作者:IT王子 更新时间:2023-10-29 01:15:56 25 4
gpt4 key购买 nike

我将 html 代码存储在一个字符串中,例如:

$html = '
<html>
<body>
<p>Hello <em>進撃の巨人</em>!</p>
random code
random code
<p>Lorem <span>ipsum<span>.</p>
</body>
</html>
';

然后我有两个句子存储在变量中:

$begin = 'Hello 進撃の巨人!';
$end = 'Lorem ipsum.';

我想在 $html 中搜索这两个句子,并去掉它们前后的所有内容。所以 $html 将变成:

$html = 'Hello <em>進撃の巨人</em>!</p>
random code
random code
<p>Lorem <span>ipsum<span>.';

我怎样才能做到这一点?请注意,$begin$end 变量没有 html 标签,但 $html 中的句子很可能有如上所示的标签。

也许是正则表达式方法?

到目前为止我尝试了什么

  • strpos() 方法。问题是 $html 在句子中包含标签,使得 $begin$end 句子不匹配。我可以在运行 strpos() 之前使用 strip_tags($html),但显然我最终会得到没有标签的 $html

  • 搜索变量的一部分,例如 Hello,但这并不安全并且会给出很多匹配项。

最佳答案

这是一个简短但 - 我相信 - 基于惰性点匹配正则表达式的工作解决方案(可以通过创建更长的展开正则表达式来改进,但应该足够了,除非你有非常大的文本 block )。

$html = "<html>\n<body>\n<p><p>H<div>ello</div><script></script> <em>進&nbsp;&nbsp;&nbsp;撃の巨人</em>!</p>\nrandom code\nrandom code\n<p>Lorem <span>ipsum<span>.</p>\n</body>\n </html>";
$begin = 'Hello 進撃の巨人!';
$end = 'Lorem ipsum.';
$begin = preg_replace_callback('~\s++(?!\z)|(\s++\z)~u', function ($m) { return !empty($m[1]) ? '' : ' '; }, $begin);
$end = preg_replace_callback('~\s++(?!\z)|(\s++\z)~u', function ($m) { return !empty($m[1]) ? '' : ' '; }, $end);
$begin_arr = preg_split('~(?=\X)~u', $begin, -1, PREG_SPLIT_NO_EMPTY);
$end_arr = preg_split('~(?=\X)~u', $end, -1, PREG_SPLIT_NO_EMPTY);
$reg = "(?s)(?:<[^<>]+>)?(?:&#?\\w+;)*\\s*" . implode("", array_map(function($x, $k) use ($begin_arr) { return ($k < count($begin_arr) - 1 ? preg_quote($x, "~") . "(?:\s*(?:<[^<>]+>|&#?\\w+;))*" : preg_quote($x, "~"));}, $begin_arr, array_keys($begin_arr)))
. "(.*?)" .
implode("", array_map(function($x, $k) use ($end_arr) { return ($k < count($end_arr) - 1 ? preg_quote($x, "~") . "(?:\s*(?:<[^<>]+>|&#?\\w+;))*" : preg_quote($x, "~"));}, $end_arr, array_keys($end_arr)));
echo $reg .PHP_EOL;
preg_match('~' . $reg . '~u', $html, $m);
print_r($m[0]);

IDEONE demo

算法:

  • 通过将分隔符字符串拆分为单个字素来创建动态正则表达式模式(因为这些可以是 Unicode 字符,我建议使用 preg_split('~(?<!^)(?=\X)~u', $end) )并通过添加可选的标签匹配模式 (?:<[^<>]+>)? 来内爆.
  • 然后,(?s) . 时启用 DOTALL 模式匹配任何字符,包括换行符和 .*?将匹配从前导到尾分隔符的 0+ 个字符。

正则表达式详细信息:

  • '~(?<!^)(?=\X)~u匹配除每个字素之前的字符串开头以外的所有位置
  • (样本最终正则表达式)(?s)(?:<[^<>]+>)?(?:&#?\w+;)*\s*H(?:\s*(?:<[^<>]+>|&#?\w+;))*e(?:\s*(?:<[^<>]+>|&#?\w+;))*l(?:\s*(?:<[^<>]+>|&#?\w+;))*l(?:\s*(?:<[^<>]+>|&#?\w+;))*o(?:\s*(?:<[^<>]+>|&#?\w+;))* (?:\s*(?:<[^<>]+>|&#?\w+;))*進(?:\s*(?:<[^<>]+>|&#?\w+;))*撃(?:\s*(?:<[^<>]+>|&#?\w+;))*の(?:\s*(?:<[^<>]+>|&#?\w+;))*巨(?:\s*(?:<[^<>]+>|&#?\w+;))*人(?:\s*(?:<[^<>]+>|&#?\w+;))*\!(?:\s*(?:<[^<>]+>|&#?\w+;))* + (.*?) + L(?:\s*(?:<[^<>]+>|&#?\w+;))*o(?:\s*(?:<[^<>]+>|&#?\w+;))*r(?:\s*(?:<[^<>]+>|&#?\w+;))*e(?:\s*(?:<[^<>]+>|&#?\w+;))*m(?:\s*(?:<[^<>]+>|&#?\w+;))* (?:\s*(?:<[^<>]+>|&#?\w+;))*i(?:\s*(?:<[^<>]+>|&#?\w+;))*p(?:\s*(?:<[^<>]+>|&#?\w+;))*s(?:\s*(?:<[^<>]+>|&#?\w+;))*u(?:\s*(?:<[^<>]+>|&#?\w+;))*m(?:\s*(?:<[^<>]+>|&#?\w+;))*\. - 带有用于标签匹配的可选子模式和 (.*?) 的前导和尾随分隔符(可能不需要捕获)在里面。
  • ~u修饰符是必需的,因为要处理 Unicode 字符串。
  • 更新:要考虑 1+ 个空格,begin 中的任何空格和 end模式可以替换为 \s+子模式来匹配输入字符串中任何类型的 1+ 空白字符。
  • 更新 2:辅助 $begin = preg_replace('~\s+~u', ' ', $begin);$end = preg_replace('~\s+~u', ' ', $end);需要考虑输入字符串中的 1+ 个空格。
  • 要考虑 HTML 实体,请在可选部分中添加另一个子模式:&#?\\w+; , 它也会匹配 &nbsp;&#123;像实体。它还以 \s* 开头匹配可选的空白,并用 * 量化(可以是零个或多个)。

关于php - 在 HTML 中搜索 2 个短语(忽略所有标签)并删除其他所有内容,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36690567/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com