我正在尝试从许多格式错误的sgml文档中提取日期元素的内容。例如,文档可以包含一个简单的日期元素,如
<DATE>4th July 1936</DATE>
或
<DATE blaAttrib="89787adjd98d9">4th July 1936</DATE>
但也可以像毛茸茸一样:
<DATE blaAttrib="89787adjd98d9">4th July 1936
<EM>spanned across multiple lines and EM element inside DATE</EM></DATE>
目标是获得“1936年7月4日”。 由于文件不大,我选择将整个内容读入变量并执行正则表达式。以下是我的Perl代码的片段:
{
local $/ = undef;
open FILE, "$file" or die "Couldn't open file: $!";
$fileContent = <FILE>;
close FILE;
if ( $fileContent =~ m/<DATE(.*)>(.*)<\/DATE>/)
{
# $2 should contain the "4th July 1936" but it did not.
}
}
不幸的是,正则表达式不适用于毛茸茸的例子。这是因为<DATE>
内部有一个<EM>
元素,它也跨越多行。
任何善良的灵魂都可以给我一些指示,指示或线索吗?
谢谢堆!
答案 0 :(得分:3)
但是从你的例子中,你可能会尝试
if ($fileContent =~ m/<DATE[^>]*>([^<]+)/) {
# use $1 here
# you may need to strip new lines
}
答案 1 :(得分:3)
使用HTML解析器。
使用HTML解析器。
请使用HTML解析器。
但对于正则表达式,我会尝试
<DATE(.*?)>(.*)<\/DATE>
这应该比KennyTM的替代方案更快......那么,为什么要捕获第二组?
答案 2 :(得分:3)
如果日期格式是固定的,您可能希望使用以下内容:
m/<DATE(.*)>([0-9]+(st|nd|rd|th)\s(January|February|March|April|May|June|July|August|September|October|November|December)\s[0-9]+)(.*)<\/DATE>/
答案 3 :(得分:3)
而不是匹配。* ,您应匹配“不是锚点的所有内容”
即:
if($string =~ /^<DATE[^>]*>([^<]+)</){
那里,$ 1是你的约会
答案 4 :(得分:2)
你应该使用非贪婪匹配和修饰符来制作。匹配换行符
my @l = (
'<DATE>4th July 1936</DATE>',
'<DATE blaAttrib="89787adjd98d9">4th July 1936</DATE>',
'<DATE blaAttrib="89787adjd98d9">4th July 1936
<EM>spanned across multiple lines and EM element inside DATE</EM></DATE>'
);
foreach(@l) {
/^<DATE.*?>(.*?)</s && print $1;
}
输出:
4th July 1936
4th July 1936
4th July 1936
答案 5 :(得分:0)
即使你的“毛茸茸”的例子也可以简化为类似的类型。如果你总是希望1)与开始标记在同一行上的实际日期 - 和2)这就是你想要的 - 那么结束标记的位置并不重要。
$fileContent =~ m/<DATE([^>]*)>\s*(\d+\p{Alpha}+\s+\p{Alpha}+\s+\d{4})/
总是会起作用。 (如果你不想在标签中找到'>'
,那么在.*
吃掉你的整条线之后不要引起这么多的回溯是一个好主意,导致表达式失败然后必须回馈并检查,退回并检查,......)
答案 6 :(得分:-4)
没有任何方法可以在多行上使用正则表达式,但你可以使用一点技巧。如果文件不大,正如您所提到的,您可以先用一些值替换所有'\ n'字符(NEW_LINE或类似的东西),或者您可以删除它们然后使用您的模式。