这是一个挑战!
正如标题所说,我想在HTML文档中匹配标签<pre>,<code>和<textarea>的内容以外的所有内容(例如,您可以尝试使用以下文本).
在我的情况下,目的是压缩html,删除\n\t\r \n和其他清理,除非在textarea中严格要求.
当我在PHP工作时,我还考虑过提取这些标签内容,在PHP中处理其余部分并在PHP中重新注入它们.但我很想知道在regexp中这样做的方法!
我尝试了这个伟大的在线编辑器:http://regex101.com/带有'msg'标志的表达式但不完全是我想要的.((?=.?)((?!<pre>).))
任何帮助将非常感激!
Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diam nonummy nibh euismod tincidunt ut laoreet dolore magna <span>aliquam</span> erat volutpat. Ut wisi enim ad minim veniam, quis nostrud exerci tation ullamcorper suscipit lobortis nisl ut aliquip ex ea commodo consequat. <pre>Duis autem vel eum iriure dolor in hendrerit in vulputate velit esse molestie consequat, vel illum dolore eu feugiat nulla facilisis at vero eros et accumsan et iusto odio dignissim qui blandit praesent luptatum zzril delenit augue duis dolore te feugait nulla facilisi. Nam liber tempor cum soluta nobis eleifend option congue nihil imperdiet doming id quod mazim placerat facer possim assum. Typi non habent claritatem insitam; est usus legentis in iis qui facit eorum claritatem.</pre> Investigationes demonstraverunt lectores legere me lius quod ii legunt saepius. Claritas est etiam processus dynamicus, qui sequitur mutationem consuetudium lectorum. <pre>Mirum est notare quam littera gothica, quam nunc putamus parum claram, anteposuerit litterarum formas humanitatis per seacula quarta decima et quinta decima.</pre> Eodem modo typi, qui nunc nobis videntur parum clari, fiant sollemnes in futurum.
你可以使用这个:
$pattern = <<<'LOD'
~
# definitions :
(?(DEFINE) (?<tagBL> pre | code | textarea | style | script )
(?<tagContent> < (\g<tagBL>) \b .*? </ \g{-1} > )
(?<tags> < [^>]* > )
(?<cdata> <!\[CDATA .*? ]]> )
(?<exclusionList> \g<tagContent> | \g<cdata> | \g<tags>)
)
# pattern :
\g<exclusionList> (*SKIP) (*FAIL) | \s+
~xsi
LOD;
$html = preg_replace($pattern, ' ', $html);
Run Code Online (Sandbox Code Playgroud)
请注意,这是一种通用方法,您可以通过在排除列表中添加或删除内容来轻松地使其适应特定情况。如果您需要其他类型的替换,您也可以通过使用捕获组和 来调整它preg_replace_callback()。
另一个注意事项:html 标签在关闭标签之前保持打开状态。如果结束标签不存在,则该标签之后的所有内容都属于该标签,直到字符串末尾。为了解决这个问题,您可以在标签内容定义中进行更改,或者编写更高级的规则</ \g{-1} >。(?: </ (?:\g{-1}| head | body | html) > | $)
编辑:您可以在php 手册
中找到一些信息:
nowdoc 语法是定义字符串的替代语法。
在不修改其布局并避免有关转义引号的问题的情况下使多行字符串更具可读性非常有用。
nowdoc 语法与单引号具有相同的行为,即变量不会被解释为转义格式标记,如\t或\n。如果您想要与双引号相同的行为,请使用heredoc语法。
您可以在http://pcre.org/pcre.txt中找到一些信息:
首先:模式分隔符
大多数时候,人们用/分隔符来书写他们的模式。但是,/Gnagnagna/当他们编写包含大约一千或一百万个斜杠字符的模式时,他们更喜欢逐个转义一千个斜杠中的每一个,以选择其他分隔符!使用 PHP,如果它不是字母数字字符,您可以选择所需的模式分隔符。我选择而不是出于以下三个原因:/blablabla/ixUums~/
~,则不必转义斜杠,因为分隔符和文字字符没有歧义。第二:如何让长图案更具可读性?
PCRE(Perl 通用正则表达式,PHP 使用的正则表达式引擎)有多种方法可以使代码更具可读性。这些方法与您在通用代码中找到的方法完全相同:
对于1和2,很简单,你只需要添加x修饰符(这就是你在末尾找到x的原因)。x 修饰符允许详细模式,其中空格被忽略,并且您可以# comment在行尾添加这样的注释。
关于子模式:您可以使用命名组,例如:~([0-9]+)~您可以编写 来匹配和捕获组 1 内的数字,而不是编写~(?<number>[0-9]+)~. 现在,通过这个命名子模式,您可以在模式中的任何位置使用 ,引用捕获的内容\g{number}或使用模式本身。\g<number>例子:
~^(?<num>[0-9]+)(?<letter>[a-z]+)\g<num>\g<letter>$~
Run Code Online (Sandbox Code Playgroud)
将匹配45ab67cd
~^(?<num>[0-9]+)(?<letter>[a-z]+)\g{num}\g<letter>$~
Run Code Online (Sandbox Code Playgroud)
会匹配45ab45cd但不匹配45ab67cd
在这两个示例中,命名子模式是主模式的一部分,并与字符串的开头匹配。但是使用(?(DEFINE)...)语法,您可以在主模式之外定义它们,因为您在这些括号之间编写的所有内容都不匹配。
~(?(DEFINE)(?<num>[0-9]+)(?<letter>[a-z]+))^\g<num>\g<letter>$~
Run Code Online (Sandbox Code Playgroud)
不匹配45ab67cd,因为DEFINE匹配时会忽略该部分内的所有内容,但是:
~(?(DEFINE)(?<num>[0-9]+)(?<letter>[a-z]+))^\g<num>\g<letter>\g<num>\g<letter>$~
Run Code Online (Sandbox Code Playgroud)
做。
第三:相对反向引用
当您在模式中使用捕获组时,您可以使用对捕获内容的引用,例如:
$str = 'cats meow because cats are bad.';
$pattern = '~^(\w+) \w+ \w+ \1 \w+ \w+\.$~';
var_dump(preg_match($pattern, $str));
Run Code Online (Sandbox Code Playgroud)
true由于模式与字符串匹配,因此返回当前代码。在模式中,指的是第一个捕获组的\1内容 ( )。cats除了编写\1,您还可以使用 oniguruma 语法并编写\g{1}引用第一个捕获组的内容,它是相同的。
现在,如果您想引用最后一个捕获组的内容,但您不关心该组的编号(或名称),则可以通过编写来使用相对引用\g{-1}(即我左边的第一个组) )
第四:修饰符xsi
模式的一般行为可以通过修饰符来更改。这里我使用了三个修饰符:
x # for verbose mode
i # make the pattern case insensitive (i.e. '~CaT~i' will match "cat")
s # (singleline mode): by default the . doesn't match newline, with the s modifier it does.
Run Code Online (Sandbox Code Playgroud)
最后:回溯控制动词
回溯控制动词是从 Perl 正则表达式引擎继承的一个实验性功能(该状态在 Perl 中也是实验性的,但如果没有人使用它,它不会改变)。
什么是回溯?
"aaaaab"如果我尝试与~a+ab~正则表达式引擎匹配,因为+是一个贪婪的量词,将捕获所有a(五个 a),但在它之后仅保留 ab与子模式不匹配ab。正则表达式引擎的唯一方法是返回一个a,然后就可以匹配ab。这是正则表达式引擎的默认行为。
回溯控制动词是强制正则表达式引擎具有您想要的子模式行为的工具。
这里我使用了两个动词:(*SKIP)和(*FAIL)
(*FAIL)是最容易的。子模式被迫立即失败。
(*SKIP):当子模式在此动词之后失败时,正则表达式引擎无权回溯在此动词之前匹配的字符。并且此内容不能重复用于其他替代子模式。
我知道所有这些事情并不总是那么容易,但我希望有一天,所有这些事情对你来说都会变得清晰。