JavaScript RegEx - 返回结果但仍无法正常工作

时间:2013-06-26 11:40:37

标签: javascript regex

我正在尝试匹配DTD节点,例如此文本:

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

使用这个正则表达式:

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

并返回所需的文字+文字'注意' - 任何人都可以解释原因吗?

此外,当我删除“note”文本任一侧的一个或两个空格时,它仍会返回结果,这是不需要的。任何人都可以帮助解释它为什么这样做吗?

这是我的测试文件:

<!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)>

提前感谢您的帮助!

4 个答案:

答案 0 :(得分:2)

这是正则表达式的样子,通过automaton

查看

Regular expression image

所以你实际上正确地匹配了你想要的东西,但你也在捕捉两组:

  1. "<!ELEMENT note (to,from,body)"
  2. "note"
  3. 但它也会匹配其他类型的字符串,例如:

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

    这些标签不是很好。

    所以你最好做一个more precise regex ,像:

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

    Regular expression image

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

    1. "<!ELEMENT note (to,from,body)>"
    2. "from,"
    3. 并且您必须获得第一个组,您只需要获取返回数组的第一个元素:

      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*>/
      

      Regular expression image

      look it up here

      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...<!ENTITY...个节点。对于那些,match将等于null。对于<!ELEMENT...个节点,它们将包含匹配节点的完整字符串。

答案 1 :(得分:1)

两者的答案都是因为你使用.*,它会将所有内容都匹配为零次或更多次。

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

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

Proof the regular expression works

A fiddle to further demonstrate this works

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

Regular expression image

总结一下,这匹配字符串<!,后跟ELEMENTENTITYATTLIST,后跟一个或多个空格(\s+) ,后跟一个或多个单词字符(\w+),后跟一个或多个空格,后跟一个或多个字符,后跟右括号。

答案 2 :(得分: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/

答案 3 :(得分:0)

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

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

另一个问题是,.也可以匹配空格。你可能应该有点限制性(这样你也可以避免不合理的量词,这通常会导致表现更差):

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

\S匹配除空格字符以外的任何内容,[^)]匹配除)个字符以外的任何字符(它是否定字符类)。实际上,您可能也希望从(中排除\S,因为否则它可能已经匹配到括号中:

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

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

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

如果note部分是可选的,我的早期版本至少需要 2 空格(由于两个\s+)。在这种情况下,您可以将note部分与以下空间分组,并将其作为可选项一起使用。这样,如果note存在,则只需要空格。要禁止捕获(因此您不会再次获得两个字符串),请使用(?:...)进行分组而不是(...)

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

请注意,match仍然会为您提供一个包含您要查找的字符串的数组(并且您无法对其执行任何操作),因此您必须使用[0]访问它。