【问题标题】:JavaScript Regex: Finding a String that does not contain </p>JavaScript 正则表达式:查找不包含 </p> 的字符串
【发布时间】:2016-02-27 08:22:34
【问题描述】:

我正在尝试编写一个正则表达式,它将在代码编辑器 (Khan Live Editor) 中找到一串 HTML 标记并给出以下错误:

"You can't put &lt;h1.. 2.. 3..&gt; inside &lt;p&gt; elements."

这是我要匹配的字符串:

<p> ... <h1>

这是我不想匹配的字符串:

<p> ... </p><h1>

相反,预期的行为是在这种情况下出现另一条错误消息。

所以在英语中我想要一个字符串;
- 以 &lt;p&gt;
开头 - 以&lt;h1&gt; 结尾,但
- 不包含&lt;/p&gt;

如果我不关心&lt;/p&gt; 的存在,这很容易完成。我的表情看起来像这样,/&lt;p&gt;.*&lt;h[1-6]&gt;/,效果很好。但我需要确保&lt;/p&gt; 不在&lt;p&gt;&lt;h1&gt; 标签之间(或任何&lt;h#&gt; 标签,因此是&lt;h[1-6]&gt;)。


我在这里的其他帖子中尝试了很多不同的表达方式:

Regular expression to match a line that doesn't contain a word?

我尝试过:&lt;p&gt;^((?!&lt;\/p&gt;).)*$&lt;/h1&gt;

regex string does not contain substring

我尝试过:/^&lt;p&gt;(?!&lt;\/p&gt;)&lt;h1&gt;$/

Regular expression that doesn't contain certain string

此链接建议:aa([^a] | a[^a])aa

这在我的情况下不起作用,因为我需要特定的字符串“&lt;/p&gt;”而不仅仅是它的字符,因为&lt;p&gt; ... &lt;h1&gt; 之间可能还有其他标签。


我真的被难住了。我尝试过的正则表达式似乎应该工作......知道我将如何使其工作吗?也许我错误地执行了其他帖子的建议?

提前感谢您的帮助。

编辑:

回答为什么我需要这样做:

问题在于&lt;p&gt;&lt;h1&gt;&lt;/h1&gt;&lt;/p&gt; 是一个语法错误,因为h1 关闭了第一个&lt;p&gt;,并且有一个不匹配的&lt;/p&gt;。原始语法错误没有提供信息,但在大多数情况下是正确的;我的例子是个例外。如果正则表达式发现此异常,我正在尝试向语法解析器传递一条新消息以覆盖原始消息。

【问题讨论】:

  • 没错。所以问题是&lt;p&gt;&lt;h1&gt;&lt;/h1&gt;&lt;/p&gt;是一个语法错误,因为h1关闭了第一个&lt;p&gt;并且有一个不匹配的&lt;/p&gt;。原始语法错误没有提供信息,但在大多数情况下是正确的;我的例子是个例外。如果正则表达式发现此异常,我正在尝试向语法解析器传递一条新消息以覆盖原始消息。
  • 这与您的正则表达式问题无关,但在显式 之前包含

    等的 html 内容实际上是正确且正确的,在 HTML5(有这个流内容规则)中,

    是完全可选的。例如:&lt;p&gt;Paragraph 1.&lt;p&gt;Paragraph 2.&lt;h2&gt;Heading&lt;/h2&gt;&lt;p&gt;Paragraph 3. 是完全有效的 HTML5,可以故意这样创作。
  • 我们是否应该假设标签中没有属性或空格?
  • @AlanMcBee 是的,没错。
  • @DanFletcher 你说 RegEx 是你唯一的选择。但是,您可以欺骗您的验证器并从参数列表中的 IIFE 传递 RegEx,并利用 Niet the Dark Absol 的代码。请check a fiddle.

标签: javascript html regex


【解决方案1】:

有时最好分解问题。

var str = "YOUR INPUT HERE";
str = str.substr(str.indexOf("<p>"));
str = str.substr(0,str.lastIndexOf("<h1>"));
if( str.indexOf("</p>") > -1) {
    // there is a <p>...</p>...<h1>
}
else {
    // there isn't
}

这段代码不能很好地处理“如果没有&lt;p&gt; 开头怎么办”的情况,但它确实给出了一个基本概念,即如何在不使用正则表达式的情况下将问题分解为更简单的部分。

【讨论】:

  • 如果不用正则表达式(不增加太多复杂性)也可以完成,那么应该完成。 +1
  • 谢谢。在这种情况下——至少目前是这样——正则表达式是我唯一的选择。
  • 这实际上是我的问题的可行解决方案。正如@Teemu 向我指出的那样,我可以将我的验证器传递给 IIFE,这样就可以了。再次感谢!
【解决方案2】:

搜索&lt;p&gt; 后跟任意数量的字符([^] 表示任何非空字符,这允许我们也捕获换行符)后面没有&lt;/p&gt;,最终后面是&lt;h[1-6]&gt; .

/<p>(?:[^](?!<\/p>))*<h[1-6]>/gi

RegEx101 Test Case

const strings = [ '<p> ... <h1>', '<p> ... </p><h1>', '<P> Hello <h1>', '<p></p><h1>',
                  '<p><h1>' ];

const regex = /<p>(?:(?!<\/p>)[^])*<h[1-6]>/gi;

const test = input => ({ input, test: regex.test(input), matches: input.match(regex) });

for(let input of strings) console.log(JSON.stringify(test(input)));

// { "input": "<p> ... <h1>",     "test": true,  "matches": ["<p> ... <h1>"]   }
// { "input": "<p> ... </p><h1>", "test": false, "matches": null               }
// { "input": "<P> Hello <h1>",   "test": true,  "matches": ["<P> Hello <h1>"] }
// { "input": "<p></p><h1>",      "test": false, "matches": null               }
// { "input": "<p><h1>",          "test": true,  "matches": ["<p><h1>"]        }
.as-console-wrapper { max-height: 100% !important; min-height: 100% !important; }

【讨论】:

    【解决方案3】:

    您的第一个正则表达式很接近,但需要删除 ^$ 字符。如果需要跨换行符匹配,则应使用[/s/S] 而不是.

    这是最终的正则表达式:&lt;p&gt;(?:(?!&lt;\/p&gt;)[\s\S])*&lt;h[1-6]&gt;

    但是,在段落元素中使用标题标签 (&lt;h1&gt; - &lt;h6&gt;) 是完全合法的。它们只是被视为同级元素,段落元素在标题元素开始处结束。

    如果 p 元素后面紧跟 addressarticle,则可以省略 p 元素的结束标记>, aside, blockquote, dir, div, dl, 字段集页脚表单h1h2h3 , h4, h5, h6, 标题, hr, 菜单, nav, ol, p, pre, section, tableul 元素,或者如果父元素中没有更多内容且父元素不是 a 元素。 p>

    http://www.w3.org/TR/html-markup/p.html

    【讨论】:

    • 哇!太感谢了!这比我需要的效果更好:) 我们捕获

      顺便说一句的原因是因为它不应该通过验证,我们正在尝试传授良好的实践。再次感谢。
    【解决方案4】:

    我得出的结论是,使用正则表达式查找错误会将您的一个问题变成两个问题。

    因此,我认为更好的方法是进行非常简单的树解析形式。一个“穷人的 HTML 解析器”,如果你愿意的话。

    使用一个简单的正则表达式来简单地查找 HTML 中的所有标签,并按照它们被发现的顺序将它们放入一个列表中。忽略标签之间的文本节点。

    然后,按顺序浏览列表,对标签保持连续计数。当你得到一个&lt;p&gt;标签时增加P计数器,当你得到一个&lt;/p&gt;标签时减少它。当您到达&lt;h1&gt;(等)标签时,增加 H 计数器和 H 计数器,减少结束标签。

    如果 H 计数器 > 0 而 P 计数器 > 0,那就是你的错误。

    【讨论】:

    • 非常感谢您抽出宝贵时间来做这件事。这肯定行得通!
    【解决方案5】:

    我知道我没有正确格式化它,但我认为逻辑会起作用,

    (只需将 AND 和 NOT 替换为正确的符号):

    /(<p>.*<h[1-6]>)AND !(<p>.*</p><h[1-6]>)/
    

    让我知道进展如何:)

    【讨论】:

    • 谢谢,但如果就这么简单,我会这么做的。我不理解它的逻辑,它正在将逻辑实现到正则表达式中。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2023-03-20
    • 1970-01-01
    • 2014-03-23
    • 2011-07-22
    • 2012-05-11
    • 2010-10-15
    • 2011-06-27
    相关资源
    最近更新 更多