我正在尝试匹配DTD节点,例如此文本:
<!ELEMENT note (to,from,body)>
使用这个正则表达式:
match(/<!ELEMENT\s?(.*?)\s?\(.*?\)>/i)
并返回所需的文字+文字'注意' - 任何人都可以解释原因吗?
此外,当我删除“note”文本任一侧的一个或两个空格时,它仍会返回结果,这是不需要的。任何人都可以帮助解释它为什么这样做吗?
这是我的测试文件:
<!ENTITY Aring "&#197;" >,
<!ENTITY aring "&#229;" >,
<!ENTITY agrave "&#224;" >,
<!ENTITY aacute "&#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)>
提前感谢您的帮助!
答案 0 :(得分:2)
这是正则表达式的样子,通过automaton:
查看
所以你实际上正确地匹配了你想要的东西,但你也在捕捉两组:
"<!ELEMENT note (to,from,body)"
"note"
但它也会匹配其他类型的字符串,例如:
<!ELEMENT%e
(jmopV|)
<!ELEMENT r()
这些标签不是很好。
所以你最好做一个more precise regex ,像:
<!ELEMENT\s+\w+\s+\((\w+, ?)*\w+\)>
<!ELEMENT
\s+
一个或多个空格\w+
一个或多个单词字符\s+
一个或多个空格\(
一个真正的括号(
小组开始\w+
或更多字符,
逗号?
一个或零个空格(可能是*
零个或多个空格))*
组的结尾,该组匹配零次或多次\w+
一个或多个单词字符\s*
)\)
右括号字符\s*
)>
结束标记字符
然后,当你match(/<!ELEMENT\s+\w+\s+\((\w+, *)*\w+\)>/i)
时,你仍会得到两组:
"<!ELEMENT note (to,from,body)>"
"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 "&#197;" >,
<!ENTITY aring "&#229;" >,
<!ENTITY agrave "&#224;" >,
<!ENTITY aacute "&#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...
或<!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
一张可爱的图片来说明比赛是如何运作的:
总结一下,这匹配字符串<!
,后跟ELEMENT
或ENTITY
或ATTLIST
,后跟一个或多个空格(\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
答案 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]
访问它。