?看起来您正在使用 XML。要解析吗?
嘿,我以前从来没有用 Perl 做过,但是有一个 Introductory Tutorial 和一切......这不是很简单。阅读XML::SAX::ParserFactory 和XML::SAX::Base 我想出了你在这个答案底部看到的代码。
问题已更新为没有相邻行;以前:
好的,我看到您有两个日期匹配的 <start> 标记和两个日期匹配的 <end> 标记在整个文件中,但它们是不同的部分。如果您的所有重复行实际上也相邻,因为它们在您的示例中是 是,那么您只需要使用来自 GNU 的 uniq 命令Coreutils 或等效的。此命令可以通过正确使用 LC_COLLATE 环境变量设置来忽略大小写,但老实说,我发现很难找到示例或 read how to use LC_COLLATE 忽略大小写。
继续解析器:
#!/usr/bin/perl
use XML::SAX;
my $parser = XML::SAX::ParserFactory->parser(
Handler => TestXMLDeduplication->new()
);
my $ret_ref = $parser->parse_file(\*TestXMLDeduplication::DATA);
close(TestXMLDeduplication::DATA);
print "\n\nDuplicates skipped: ", $ret_ref->{skipped}, "\n";
print "Duplicates cut: ", $ret_ref->{cut}, "\n";
package TestXMLDeduplication;
use base qw(XML::SAX::Base);
my $inUserinterface;
my $inUpath;
my $upathSeen;
my $defaultOut;
my $currentOut;
my $buffer;
my %seen;
my %ret;
sub new {
# Idealy STDOUT would be an argument
my $type = shift;
#open $defaultOut, '>&', STDOUT or die "Opening STDOUT failed: $!";
$defaultOut = *STDOUT;
$currentOut = $defaultOut;
return bless {}, $type;
}
sub start_document {
%ret = ();
$inUserinterface = 0;
$inUpath = 0;
$upathSeen = 0;
}
sub end_document {
return \%ret;
}
sub start_element {
my ($self, $element) = @_;
if ('userinterface' eq $element->{Name}) {
$inUserinterface++;
%seen = ();
}
if ('upath' eq $element->{Name}) {
$buffer = q{};
undef $currentOut;
open($currentOut, '>>', \$buffer) or die "Opening buffer failed: $!";
$inUpath++;
}
print $currentOut '<', $element->{Name};
print $currentOut attributes($element->{Attributes});
print $currentOut '>';
}
sub end_element {
my ($self, $element) = @_;
print $currentOut '</', $element->{Name};
print $currentOut '>';
if ('userinterface' eq $element->{Name}) {
$inUserinterface--;
}
if ('upath' eq $element->{Name}) {
close($currentOut);
$currentOut = $defaultOut;
# Check if what's in upath was seen (lower-cased)
if ($inUserinterface && $inUpath) {
if (!exists $seen{lc($buffer)}) {
print $currentOut $buffer;
} else {
$ret{skipped}++;
$ret{cut} .= $buffer;
}
$seen{lc($buffer)} = 1;
}
$inUpath--;
}
}
sub characters {
# Note that this also capture indentation and newlines between tags etc.
my ($self, $characters) = @_;
print $currentOut $characters->{Data};
}
sub attributes {
my ($attributesRef) = @_;
my %attributes = %$attributesRef;
foreach my $a (values %attributes) {
my $v = $a->{Value};
# See also XML::Quote
$v =~ s/&/&/g;
$v =~ s/</</g;
$v =~ s/>/>/g;
$v =~ s/"/"/g;
print $currentOut ' ', $a->{Name}, '="', $v, '"';
}
}
__DATA__
<package>
<id>1523456789</id>
<models>
<model type="A">
<start>2016-04-20</start>
<end>2017-04-20</end>
</model>
<model type="B">
<start>2016-04-20</start>
<end>2017-04-20</end>
</model>
</models>
<userinterface>
<upath>/Example/Dir/Here</upath>
<upath>/Example/Dir/Here2</upath>
<upath>/example/dir/here</upath>
</userinterface>
<userinterface>
<upath>/Example/Dir/<b>Here</b></upath> <upath>/Example/Dir/Here2</upath>
<upath>/example/dir/<b>here</b></upath>
</userinterface>
</package>
这不再按行工作,而是在userinterface 标记内找到upath 标记,如果它们在该父组中重复,则会将其删除。保留周围的缩进和换行符。如果upath 标签中有upath 标签,那也会有点奇怪。
看起来像这样:
$ perl saxEG.pl
<package>
<id>1523456789</id>
<models>
<model type="A">
<start>2016-04-20</start>
<end>2017-04-20</end>
</model>
<model type="B">
<start>2016-04-20</start>
<end>2017-04-20</end>
</model>
</models>
<userinterface>
<upath>/Example/Dir/Here</upath>
<upath>/Example/Dir/Here2</upath>
</userinterface>
<userinterface>
<upath>/Example/Dir/<b>Here</b></upath> <upath>/Example/Dir/Here2</upath>
</userinterface>
</package>
Duplicates skipped: 2
Duplicates cut: <upath>/example/dir/here</upath><upath>/example/dir/<b>here</b></upath>