我需要找到基于模式的列表,并添加或删除其他字符串...
我在文件中有一个URL的xml列表。
在我的文件中,单行显示:
"xml" : "SOMESTUFFWEDONOTCARE<node n=\"Group1\" u-l=\"toto.com;tata.com;tutu.com\"></node><node n=\"Group2\" u-l=\"bobo.com;baba.com\"></node><node n=\"Group3\" u-l=\"toto.com;papa.com;pepe.com;pupu.com\"></node>SOMESTUFFWEDONOTCARE"
我的问题:
所以u-l=\"toto.com;tata.com;tutu.com\"
变成u-l=\"toto.com;tata.com;tutu.com;newwebsite.com\"
我当然只知道“ Group1”和“ newwebsite.com” ...
所以u-l=\"toto.com;papa.com;pepe.com;pupu.com\"
变成u-l=\"papa.com;pepe.com;pupu.com\"
它一定不能从Group1中删除“ toto.com”,并且我假设我不知道“ toto.com”在Group3列表中的位置(位置1到N)。
解决方案可以是perl代码(作为文件处理程序在文件上工作)或perl代码中的“ sed”(直接与文件一起工作)。 我不想将xml放入哈希并对其进行处理(我已经尝试过并且基本上可以正常工作,但是当我们再次将所有内容都放入文件中时,由于带有重音符号,换行符或非utf-8的原因,这是一团糟字符,输出与输入永远不匹配...
答案 0 :(得分:1)
仅通过解析JSON即可实现。我怀疑在不解析JSON的情况下这样做是个好主意。
我编写了一个可以修改组,添加以及从中删除域的实现。您需要记住,用正则表达式更改XML中的内容总是脆弱而幼稚的。由于它依赖于正确顺序的事物,因此它很容易崩溃。它不知道XML标记内的属性,甚至不知道标记本身。只是一堆文字。
话虽如此,让我们先来看一下配置和实际调用。
use strict;
use warnings;
use JSON;
my $json =
q[{"xml" :"SOMESTUFFWEDONOTCARE<node n=\"Group1\" u-l=\"toto.com;tata.com;tutu.com\"></node><node n=\"Group2\" u-l=\"bobo.com;baba.com\"></node><node n=\"Group3\" u-l=\"toto.com;papa.com;pepe.com;pupu.com\"></node>SOMESTUFFWEDONOTCARE"}];
my $hash = decode_json $json;
$hash->{xml} = process(
$hash->{xml} => {
"Group1" => {add => [qw/newwebsite.com/]},
"Group3" => {remove => [qw/toto.com/]}
},
);
print encode_json($hash);
第一个假设是,您提供给我们的数据字符串(看起来像JSON)实际上是JSON,并且用反斜杠转义是逐字逐句的。如果更改,则所有代码都会中断。
这里有一个配置,使您可以说要从一个组中add
和/或remove
中访问域。
这是在process
子项中完成的,它将对组进行迭代,在XML字符串中找到第一个匹配项并进行处理。假定整个XML文档在一行中。如果有换行符,则会中断。
这是全部功能。
sub process {
my ($xml, $args) = @_;
foreach my $group (keys %$args) {
if ($xml =~ m/<node n="\Q$group\E" u-l="([^"]+)">/) {
my $existing_list = $1;
my @items = split /;/, $existing_list;
# remove items from the list
if (exists $args->{$group}->{remove}) {
no warnings 'experimental';
my @remove = @{$args->{$group}->{remove}};
@items = grep { not $_ ~~ @remove } @items;
}
# add new items to the list
if (exists $args->{$group}->{add}) {
push @items, @{$args->{$group}->{add}};
}
# serialise the list and stick it back in
# need the "" as an anchor
my $new_list = join ';', @items;
$xml =~ s/"(\Q$existing_list\E)"/"$new_list"/;
}
}
return $xml;
}
请记住,尽管它看起来像XML,但我们将其视为一堆文本。我们需要<node>
的左,右括号作为锚点。我们获取域列表并进行操作。如果有多余的空格或元素顺序更改,则会中断。
代码使用简单的列表操作来处理域列表。
为便于轻松删除多个域,它使用了实验性的smartmatch运算符。您可以用其他方式实现它,但是我很懒。由于这是实验性的,因此只能在某些Perl版本上使用。
然后,通过将新列表替换为旧列表,将新列表重新粘贴到看起来像XML的大字符串中。我们需要确保没有特殊字符(例如点.
)进入模式,因此我们用\Q
和\E
对其进行转义。
如果还不清楚,我再说一遍。尽管这对您在问题中给出的非常具体的参数集有效,但有可能在您的生产环境中无法完全发挥作用。您将不得不适应它,并且可能经常适应它。
最好同时使用JSON解析器和XML解析器。
答案 1 :(得分:0)
我相信这可行。我正在使用perl正则表达式替换技术。希望我不要误解这个问题。
my $line = '"xml" : "SOMESTUFFWEDONOTCARE<node n=\"Group1\" u-l=\"toto.com;tata.com;tutu.com\"></node><node n=\"Group2\" u-l=\"bobo.com;baba.com\"></node><node n=\"Group3\" u-l=\"toto.com;papa.com;pepe.com;pupu.com\"></node>SOMESTUFFWEDONOTCARE"';
my $new_word = "newwebsite.com";
my $remove_word = "toto.com";
print $line;
$line =~ s/(.+)\\\"(Group1\\\" u-l=\\\".+.com)(\\\"\>\<\/node\>\<node n=\\\"Group2.+)(Group3\\\" u-l=\\\".+.com)(.+)/$1.$2.';'.${new_word}.$3.'***'.rm_string($4,$remove_word).$5/e;
print("\n\n$line");
sub rm_string{
$string = shift;
$remove_string=shift;
$string =~ s/$remove_string;?//;
$string =~ s/;$//;
return($string);
}
结果替换后给出-
"xml" : "SOMESTUFFWEDONOTCARE<node n=Group1\" u-l=\"toto.com;tata.com;tutu.com;newwebsite.com\"></node><node n=\"Group2\" u-l=\"bobo.com;baba.com\"></node><node n=\"***Group3\" u-l=\"papa.com;pepe.com;pupu.com\"></node>SOMESTUFFWEDONOTCARE"
答案 2 :(得分:0)
通过gnu sed将您的数据字符串保存在“ d”文件中
sed -E 's/(Group1\\.[^>]+)\"(><)/\1;newwebsite.com"\2/i; s/(Group3\\"[^=]+=\\")toto\.com;/\1/i' d