在Perl中,如何从双引号中除去字符串中的空格,并用||替换这些引号?

时间:2012-06-27 18:21:29

标签: regex perl

我试图找到一种用管道(||)替换空格和双引号的方法,同时保持双引号内的空格不变。

例如,它会产生类似' word" word word"字'进入' word || word word || word'和另一个喜欢单词的单词'进入' word || word || word'。

现在我可以解决这个问题:

[%- MACRO typestrip(value) PERL -%]
my $htmlVal = $stash->get('value');
$htmlVal =~ s/"/||/g;
print $htmlVal
[%- END -%]

哪个处理用管道替换双引号就好了。

我不知道这应该是多么简单或复杂,或者甚至可以做到,因为我没有编程的实际背景,虽然我使用过一些Perl,但它从来没有过以前这种情况,所以如果我没有做好解释,我会道歉。

4 个答案:

答案 0 :(得分:9)

我认为使用核心模块Text::ParseWords拆分非引用的空格可能更容易,然后用管道重新加入“单词”。

#!/usr/bin/env perl

use warnings;
use strict;

use Text::ParseWords;

while (my $line = <DATA>) {
  print space2pipes($line); 
  print "\n";
}

sub space2pipes {
  my $line = shift;
  chomp $line;
  my @words = parse_line( qr/\s+/, 0, $line );
  return join '||', @words;
}

__DATA__
word "word word" word
word word word

将它放入你的模板引擎中留给读者练习: - )

答案 1 :(得分:4)

这与常见问题answered in section 4 of the Perl FAQ有关。

  

如何在[字符]内部拆分[字符] - 分隔字符串?

     

有几个模块可以处理这种解析 - Text::BalancedText::CSVText::CSV_XSText::ParseWords等。

     

以示例的方式尝试将逗号分隔的字符串拆分为不同的字段。您无法使用split(/,/),因为如果逗号在引号内,则不应拆分。例如,采用如下数据行:

SAR001,"","Cimetrix, Inc","Bob Smith","CAM",N,8,1,0,7,"Error, Core Dumped"
     

由于报价的限制,这是一个相当复杂的问题。值得庆幸的是,我们有掌握正则表达式的作者Jeffrey Friedl为我们处理这些问题。他建议(假设你的字符串包含在$text中):

my @new = ();
push(@new, $+) while $text =~ m{
           # groups the phrase inside the quotes
             "([^\"\\]*(?:\\.[^\"\\]*)*)",?
           | ([^,]+),?
           | ,
     }gx;
push(@new, undef) if substr($text,-1,1) eq ',';
     

如果要在引号分隔的字段中表示引号,请使用反斜杠(例如"like \"this\"")对其进行转义。

     

或者,Text::ParseWords模块(标准Perl发行版的一部分)允许您说:

use Text::ParseWords;
@new = quotewords(",", 0, $text);
     

但是,对于解析或生成CSV,强烈建议使用Text::CSV而不是自己实现它;你可以通过使用已经在生产中经过多年尝试和测试的代码来保存自己的奇怪错误。

根据您的情况调整技术

my $htmlVal = 'word "word word" word';

my @chunks;
push @chunks, $+ while $htmlVal =~ m{
    "([^\"\\]*(?:\\.[^\"\\]*)*)"
  | (\S+)
}gx;

$htmlVal = join "||", @chunks;
print $htmlVal, "\n";

输出:

word||word word||word

回顾过去,事实证明这是兰德尔规则的应用,正如马克·多米努斯在Regular Expression Mastery所称:

  

兰德尔的规则

           
    

当您知道要保留的内容时,请使用捕获或m//g

         

当您知道要丢弃的内容时,请使用split

  
     

Randal Schwartz

在您的情况下,您知道要保留的内容,因此请使用m//g挂起引号内的文本或以空格分隔。

答案 2 :(得分:1)

Joel's answer is fine虽然可以通过专门使用shellwords标记行来简化一些事情:

#!/usr/bin/env perl

use strict; use warnings;
use Text::ParseWords qw( shellwords );

my @strings = (
    'word "word word" word',
    'word "word word" "word word"',
);

@strings = map join('||', shellwords($_)), @strings;

use YAML;
print Dump \@strings;

是不是比一堆正则表达式gobbledygook更具可读性?

答案 3 :(得分:0)

如果只有正则表达式适用,似乎可能并且可能有用:

 $htmlVal =~ s/(?:"([^"]+)"(\s*))|(?:(\S+)(\s*))/($1||$3).($2||$4?'||':'')/eg;

(仔细反省后可能会有点美化。)

输入:

 my $htmlVal ='word "word word" word';

输出:

 word||word word||word

<小时/> 在失败的情况下修改了原始代码:

 my $htmlVal ='word "word word" "word word"';

现在也可以使用:

 word||word word||word word

<小时/> 说明:

 $htmlVal =~ s/
               (?: " ([^"]+) " (\s*)) # search "abc abc" ($1), End ($2)
               |                      # OR
               (?: (\S+) (\s*))       # abcd ($3), End ($4)
              /
               ($1||$3) . ($2||$4 ? '||' : '') # decide on $1/$2 or $3/$4 
              /exg;

此致

RBO