2

I am trying to match a DTD node such as this text:

<!ELEMENT note (to,from,body)>

With this regular expression:

match(/<!ELEMENT\s?(.*?)\s?\(.*?\)>/i)

and it returns the desired text + the text 'note' -can anyone explain why?

Also, when I remove either or both of the blank spaces either side of the 'note' text it still returns the result, and this is not wanted. Can anyone help explain why it is doing that too?

Here is my test file:

<!ENTITY Aring "&amp;#197;" >,
<!ENTITY aring "&amp;#229;" >,
<!ENTITY agrave "&amp;#224;" >,
<!ENTITY aacute "&amp;#225;" >,
<!ATTLIST ARTICLE AUTHOR CDATA #REQUIRED>,
<!ATTLIST ARTICLE EDITOR CDATA #IMPLIED>,
<!ATTLIST ARTICLE DATE CDATA #IMPLIED>,
<!ATTLIST ARTICLE EDITION CDATA #IMPLIED>,
<!ELEMENT note (to,from,heading,body)>,
<!ELEMENT to (#PCDATA)>,
<!ELEMENT from (#PCDATA)>,
<!ELEMENT heading (#PCDATA)>,
<!ELEMENT body (#PCDATA)>

Thanks in advance for any help!

4

4 回答 4

2

这是您的正则表达式的样子,通过自动机查看:

正则表达式图片

因此,您实际上正确匹配了您想要的内容,但您还捕获了两个组:

  1. "<!ELEMENT note (to,from,body)"
  2. "note"

但它也会匹配其他类型的字符串,例如:

  • <!ELEMENT%e
(jmopV|)
  • <!ELEMENT r()

这不是格式良好的标签。

所以你最好想做一个更精确的 regex ,比如:

<!ELEMENT\s+\w+\s+\((\w+, ?)*\w+\)>
  • 这是正则表达式匹配的内容:
    • 文本<!ELEMENT
    • \s+一个或多个空间
    • \w+一个或多个单词字符
    • \s+一个或多个空间
    • \(一个真正的括号
    • (一组开始
    • \w+单词字符中的一个或多个
    • ,逗号
    • ?一个或零个空格(可以是*零个或多个空格)
    • )*组的末尾,该组匹配零次或多次
    • \w+一个或多个单词字符
    • \s*(如果您想在右括号前匹配可选空格,您可能需要添加)
    • \)右括号字符
    • \s*(如果您想在标签末尾匹配可选空格,您可能需要添加)
    • >结束标记字符

正则表达式图片

然后,当你这样做时match(/<!ELEMENT\s+\w+\s+\((\w+, *)*\w+\)>/i),你仍然会得到两组:

  1. "<!ELEMENT note (to,from,body)>"
  2. "from,"

你必须得到第一组,你只需要得到返回数组的第一个元素:

var match = "<!ELEMENT note (to,from,body)>".match(/<!ELEMENT\s+\w+\s+\((\w+, *)*\w+\)>/i);
if (match !== null)
    match = match[0];

如果你想使用 regexp 对象这样做:

pattern = new RegExp(/<!ELEMENT\s+\w+\s+\((\w+, *)*\w+\)>/i)
match = pattern.exec(text)
if (match !== null)
    match = match[0]

这将为您提供第一组比赛(即完整比赛)。

编辑后:

你想要一个适用于这组值的正则表达式:

<!ENTITY Aring "&amp;#197;" >,
<!ENTITY aring "&amp;#229;" >,
<!ENTITY agrave "&amp;#224;" >,
<!ENTITY aacute  "&amp;#225;" >,
<!ATTLIST ARTICLE AUTHOR CDATA #REQUIRED>,
<!ATTLIST ARTICLE EDITOR CDATA #IMPLIED>,
<!ATTLIST ARTICLE DATE CDATA #IMPLIED>,
<!ATTLIST ARTICLE EDITION CDATA #IMPLIED>,
<!ELEMENT note (to,from,heading,body)>,
<!ELEMENT to (#PCDATA)>,
<!ELEMENT from (#PCDATA)>,
<!ELEMENT heading (#PCDATA)>,
<!ELEMENT body (#PCDATA)>

所以你想要一个看起来像这样的正则表达式:

/<!ELEMENT\s+\w+\s+\((\#?\w+,\s*)*\#?\w+\s*\)\s*>/

正则表达式图片

在这里查找

var match = "<!ELEMENT note (to,from,body)>".match(/<!ELEMENT\s+\w+\s+\((\#?\w+,\s*)*\#?\w+\s*\)\s*>/i);
if (match !== null)
    match = match[0];

在那里它只匹配<!ELEMENT...节点,而不是<!ATTLIST...or<!ENTITY...节点。对于那些,match将等于null。对于<!ELEMENT...节点,它们将包含匹配节点的完整字符串。

于 2013-06-26T11:59:05.687 回答
1

两者的答案都是因为您正在使用.*,它匹配所有内容零次或多次。

相反,请使用以下正则表达式:

/<!(?:ELEMENT|ENTITY|ATTLIST)\s+\w+\s+.+>/i

证明正则表达式有效

进一步展示这项工作的小提琴

还有一张可爱的图片来说明比赛是如何运作的:

正则表达式图片

总而言之,这匹配字符串<!,后跟ELEMENTorENTITYATTLIST,后跟 1 个或多个空格 ( \s+),后跟 1 个或多个单词字符 ( \w+),后跟 1 个或多个空格,后跟一个或多个字符,然后是右括号。

于 2013-06-26T11:47:17.210 回答
1

提供注释部分是固定的:

var node = '<!ELEMENT note (to,from,body)>';
node.match(/<!ELEMENT note \(.+,.+,.+\)/); // Will alert the whole element

var invalidNode = '<!ELEMENTnote (to,from,body)>';
invalidNode.match(/<!ELEMENT note \(.+,.+,.+\)/); // Will return null

见:http: //jsfiddle.net/a5KkF/

于 2013-06-26T11:56:52.560 回答
0

你得到的原因note捕获. 括号组使匹配的那部分稍后可用(或在反向引用中)。由于您甚至不需要括号进行分组,因此如果您不想要,只需删除它们note

然后你的空格是可选的(由于?) - 因此,在字符串中删除它们根本无关紧要。只需删除?或将其设为 a +(以便允许多个空格)。

另一个问题是,它.也可以匹配空格。您可能应该更具限制性(这样您还可以避免不贪婪的量词,这些量词通常在性能上更差):

/<!ELEMENT\s+\S*\s+\([^)]*\)>/i

\S匹配除空格字符以外的任何字符,并[^)]匹配除字符以外的任何)字符(它是一个否定字符类)。事实上,您可能也想(从中排除\S,否则它可能已经匹配到括号中:

/<!ELEMENT\s+[^\s(]*\s+\([^)]*\)>/i

如果该note部分必须包含至少一个字符,您也应该在正则表达式中明确这一点,使用+代替*

/<!ELEMENT\s+[^\s(]+\s+\([^)]*\)>/i

note另一方面,如果该部分是可选的,我的早期版本至少需要2 个空格(由于两个\s+)。在这种情况下,您可以将该note部分与以下空格组合在一起,并将其设为可选。这样你只需要空间,如果note有的话。要禁止捕获(这样您就不会再次获得两个字符串),请使用(?:...)for grouping 而不是(...)

/<!ELEMENT\s+(?:[^\s(]+\s+)?\([^)]*\)>/i

请注意,它match仍然会为您提供一个包含您要查找的字符串的数组(并且您对此无能为力),因此您必须使用[0].

于 2013-06-26T11:45:04.857 回答