正则表达式将匹配包含../的每个特定标记

时间:2015-03-08 04:05:08

标签: php html regex

我试图找到一个匹配包含../的每个特定标记的正则表达式。 当每个元素都在自己的行上时,我将它匹配。但是有一个实例,我的HTML在一行上呈现,导致正则表达式匹配整行:

<body><img src="../../../img.png"><img src="../../img.png"><img src="../../img.png"><img src="..//../img.png"><img src="..../../img.png">

这是我正在使用的正则表达式

<.*[\.]{2}[\/].*>

3 个答案:

答案 0 :(得分:1)

您需要确保每场比赛只匹配一个标签。 使用如下的负面字符类就可以实现这一目标。

<[^>]*\.\./[^>]*>

< =标记开头

[^>]* = 不是 >的任意数量的字符,因为>会结束标记

\.\./ =“../”,包含.字符的转义

[^>]* =与上述相同

> =代码结束

看起来您可能正在这样做以防止路径育儿。您应该知道,对于HTML标记中的URL属性,以下标记被视为“等效”:

<img src="../foo.jpg">
<img src="%2e%2e%2ffoo.jpg">
<img src="&#46;&#46;/foo.jpg">

这是因为src属性在使用之前通过HTML实体取消转义,然后URL取消转义(按此顺序)。因此,有5,832种不同的方法可以将'../'写入HTML标记的路径属性(18种方法可以将每个字符写入3个字符)。

使正则表达式匹配../的任何编码都比较困难,但仍有可能。

(\.|&#46;|(%|&#37;)(2|&#50;)([Ee]|&#69;|&#101;)){2}(/|&#47;|(%|&#37;)(2|&#50;)([Ff]|&#70;|&#102;))

供参考:

&#46; = . HTML转义序列

&#47; = / HTML转义序列

%2E%2e = .网址转义序列

%2F%2f = /网址转义序列

&#37; = % HTML转义序列

&#50; = 2 HTML转义序列

&#69; = E HTML转义序列

&#101; = e HTML转义序列

&#70; = F HTML转义序列

&#102; = f HTML转义序列

你可以看到为什么人们通常会说使用真正的HTML解析器而不是正则表达式更好!

无论如何,假设您需要这个,并且完整的HTML解析器不可行,这里的<[^>]*[="'/]\.\./[^>]*>版本也会捕获HTML和URL转义:

<[^>]*[="'/](\.|&#46;|(%|&#37;)(2|&#50;)([Ee]|&#69;|&#101;)){2}(/|&#47;|(%|&#37;)(2|&#50;)([Ff]|&#70;|&#102;))[^>]*>

答案 1 :(得分:0)

导致regex与整条线匹配,似乎你regex贪婪,请尝试@Avinash Raj评论。

enter image description here

DEMO

答案 2 :(得分:0)

要获得您想要的正则表达式,我将尝试按照一步一步的方法:

  • 首先,我们需要一些匹配标记开头和结尾的正则表达式。但我们必须小心,因为单引号和双引号字符串中允许使用标记结束字符>。我们首先构造匹配这些单/双引号字符串的正则表达式:([^"'>]|"[^"]*"|'[^']*')*(序列:非引用(单引号和双引号)和非结束标记字符,或单引号字符串,或双引号字符串)

  • 现在,修改它以匹配单引号字符串或包含../的双引号字符串:([^"'>]|"[^"]*\.\.\/[^"]*"|'[^']*\.\.\/[^']*')*(我们可以简化它,消除最后*运算符,因为我们将整个字符串与仅匹配../内的一个匹配,我们可以删除第一个选项,因为我们将在引用的字符串中包含../ seq。我们到达:("[^"]*\.\.\/[^"]*"|'[^']*\.\.\/[^']*')

  • 为了得到一个匹配包含至少一个第二个字符串的序列的字符串,我们在开头和结尾连接第一个正则表达式,在中间连接另一个正则表达式。我们到达:([^"'>]|"[^"]*"|'[^']*')*("[^"]*\.\.\/[^"]*"|'[^']*\.\.\/[^']*')([^"'>]|"[^"]*"|'[^']*')*

  • 现在,我们只需要首先使用所需的序列<[iI][mM][gG][ \t\n]包围此正则表达式,然后在>之后,转到:

    <[iI][mM][gG][ \t\n]([^"'>]|"[^"]*"|'[^']*')*("[^"]*\.\.\/[^"]*"|'[^']*\.\.\/[^']*')([^"'>]|"[^"]*"|'[^']*')*>

这是我们需要的正则表达式。请参阅demo如果我们提取第二组的内容($2\2等),我们将获得匹配的参数值(包括引号) ../字符串。

请勿尝试进一步简化此操作,因为单引号和双引号字符串中允许使用>个字符,并且单引号字符串中允许使用",并且'位于双引号字符串。正如有人在这个问题的另一个答案中解释的那样,你不能贪婪(在里面使用.*,因为你在匹配之前会尽可能多地输入输入)这个正则表达式需要匹配多行标签,因为这些可以成为输入文件的一部分。如果你有一个格式正确的HTML文件,那么你对这个正则表达式没有任何问题。

还有一些最终引用:HTML标记由语法定义(它只是完整HTML语法的常规子集),所以它是使用正则表达式完全可解析(对于完整的HTML语言也是如此)正则表达式比完整的HTML解析器效率更高,资源消耗更少。需要注意的是,你必须编写它(并写得很好)并且HTML解析器很容易找到一些谷歌搜索,避免你这样做的工作,但你必须只写一次。 Regexp解析是一个单一过程,其复杂性(对于此示例,至少)与输入文本长度呈线性增长。对于那些根本不知道如何编写正确的正则表达式或者不知道如何确定某些语法是否正常的人,建议您不要这样做。

注意:

此正则表达式将匹配已注释的标记。如果您不想匹配已注释的<img>标记,则必须先扩展您的正则表达式,或者先执行两遍以消除注释,然后解析标记(仅限正则表达式)识别未注释的标签远比这复杂得多)另外,请看下面的更多困难,你可以在任务上消除父目录引用。

注2:

正如我在您的评论中读到的一些答案,您要解决的问题(消除HTML / XML源中的..引用)并不常见。原因是您可以在路径字符串中嵌入...引用。通常,必须继续消除路径的/../组件,获取没有.(实际目录)引用的路径。完成此操作后,您必须删除a/..引用,其中a..不同。这有助于消除a/..a/b/../..等的出现。但匹配a^i b^i的语言并不规律(如抽水引理所示 - 请参阅谷歌)和您#39 ; ll需要一个与上下文无关的语法。

注3:

如果您将a/b/c/../../..级别的数量限制为某个最大界限,您仍然可以找到匹配此类字符串的正则表达式,但是您可以使用一个示例来打破正则表达式并使它无效。请记住,您首先必须消除单点.路径组件(因为您可以使用a/b/./././c/./d/.././e/f/.././../..。您将首先消除单点组件,导致:a/b/c/d/../e/f/../../../..。然后您继续成对<non ..>/..,获取a/b/c/[d/..]/e/f/../../../..a/b/c/e/[f/..]/../../.. - &gt; a/b/c/[e/..]/../.. - &gt; a/b/[c/..]/.. - &gt; a/[b/..] - &gt; { {1}}(您应该检查一对中的所有第一个组件是否确实存在,然后才能准确删除)如果您到达一个空路径,则必须将其更改为a才能使用

我有代码来执行此过程,但它已嵌入到更大的程序中。如果您有兴趣,可以访问this code。 (查看.例程here

你不能在路径的开头消除rel_path()元素(更好的是,没有..对应元素),因为它引用了树的外部,使得引用依赖于外部树的结构。