使用perl加入,分割和映射以创建新的attribs

时间:2016-12-02 07:23:04

标签: regex perl dictionary

my $str = "<SampleElement oldattribs=\"sa1 sa2 sa3\">";

$str =~ s#<SampleElement[^>]*oldattribs="([^"]*)"#
          my $fulcnt=$&;
          my $afids=$1;
          my @affs = ();
          if($afids =~ m/\s+/) {
              @affs = split /\s/, $afids; 
              my $jnafs = join ",", map { $_=~s/[a-z]*//i, } @affs;
              ($fulcnt." newattribs=\"$jnafs\"");
          }
          else {
              ($fulcnt);
          }
         #eg;

我的输出:

<SampleElement oldattribs="sa1 sa2 sa3" newattribs="1,1,1">

预期产出:

<SampleElement oldattribs="sa1 sa2 sa3" newattribs="1,2,3">

有人可以指出我在哪里做错了。提前谢谢。

3 个答案:

答案 0 :(得分:3)

您出错的地方比您想象的要早 - 您正在使用正则表达式解析XML。 XML是上下文的,而正则表达式不是so it's NEVER going to be better than a dirty hack.

#!/usr/bin/env perl
use strict;
use warnings;

use XML::Twig;
my $twig = XML::Twig -> parse ( \*DATA );

my $sample_elt = $twig -> get_xpath('//SampleElement',0); 
my @old_att = split ( ' ', $sample_elt -> att('oldattribs') );
$sample_elt -> set_att('newattribs', join " ", map { /(\d+)/ } @old_att);

$twig -> set_pretty_print ( 'indented_a' );
$twig -> print;


__DATA__
<XML>
    <SampleElement oldattribs="sa1 sa2 sa3">
    </SampleElement>
</XML>

但是要回答问题的核心 - 你在这里误用map作为迭代器。

map { $_=~s/[a-z]*//i, } @affs;

因为正在做的正在迭代@affs中的所有元素并修改那些......但是map只是返回表达式的结果 - 这是{ {1}}因为它有效。

如果您希望更改1,请执行以下操作:

@affs

但如果没有想要,那么简单的答案是使用s/[a-z]*//i for @affs; 正则表达式标志:

r

或者就像我在我的例子中所做的那样:

map { s/[a-z]*//ir } @affs;

哪个正则表达式匹配并捕获字符串的数字部分,但结果是“捕获”文本是返回的内容。

答案 1 :(得分:1)

这是一种从输入$str构建显示输出的简单方法。

注意:输入是单引号,而不是双引号。那么\"在正则表达式中不是问题。

my $str = '<SampleElement oldattribs=\"sa1 sa2 sa3\">';

# Pull 'sa1 sa2 sa3' string out of it
my ($attrs) = $str =~ /=\\"([^\\]+)/;    # " # (turn off bad syntax highlight)

# Build '1,2,3' string from it
my $indices = join ',', map { /(\d+)/ } split ' ', $attrs;

# Extract content between < > so to add to it, put it back together
my ($content) = $str =~ /<(.*)>/;    
my $outout = '<' . $content . " newattribs=\"$indices\"" . '>';

这提供了所需的输出。

如果您参与其中,其中一些可以组合成单个语句。例如

my $indices = 
    join ',', map { /(\d+)/ } split ' ', ($str =~ /"([^\\]+)/)[0];   # "

$str =~ s/<(.*)>/<$1 newattribs=\"$indices\">/;

所有这些都可以进入一个正则表达式,但它变得笨拙且难以维护。

最重要的是 - 这似乎是XML或类似的......请不要手工完成,除非只有一两个片段。有很好的解析器。

答案 2 :(得分:0)

通过搜索地图功能找到解决方案:

my $str = "<SampleElement oldattribs=\"sa1 sa2 sa3\">";

$str=~s#<SampleElement[^>]*oldattribs="([^"]*)"#my $fulcnt=$&; my $afids=$1;
my @affs = ();
if($afids=~m/\s+/)
{
    @affs = split /\s/, $afids; 
    my @newas = join ",", map { (my $foo = $_) =~ s/[a-z]*//i; $foo; } @affs ;
    ($fulcnt." newattribs=\"@newas\"");
}
else
{
    ($fulcnt);
}
#eg;

我在代码中更新了以下行:

my @newas = join ",", map { (my $foo = $_) =~ s/[a-z]*//i; $foo; } @affs ;
  

而不是

my $jnafs = join ",", map { $_=~s/[a-z]*//i, } @affs;

对所有人表示感谢。