来自数组的串联字符串变量在Perl中给出了意外的引号

时间:2014-03-19 15:02:53

标签: arrays string perl concatenation

我有一个CSV文件,我需要将每个值括在引号中,其中每个值都是一个字符串。连接时我得到了意想不到的引号

$outline = "";
$line = "John,Smith,jsmith@bogusaddress.net,000-0000";
@parts = split (',',$line);
for $part (@parts) {
    $part = '"' . $part . '"';
    if ($outline eq "") {
        $outline = $part;                  # reconstruct line
    } else {
        $outline = $outline . "," . $part;
    }
}
$outline = $outline . "," . '"' . $parts[0] . " " . $parts[1] . '"';
print "$outline\n";

我期待:

"John","Smith","jsmith.net","000-0000","John Smith"

但我得到了:

"John","Smith","jsmith.net","000-0000",""John" "Smith""

为什么我会得到额外的报价?

感谢您的帮助。

4 个答案:

答案 0 :(得分:6)

已提供了许多实用的解决方案,但我想解决您的问题:为什么会这样?

您获得双引号的原因是您实际上正在更改@parts的元素。在for循环中,元素被赋予循环参数的别名,因此对它们的任何更改都直接在" real"价值观也是如此。请考虑以下事项:

my @foos = 1 .. 3;
for my $foo (@foos) {
    $foo += 1;
}
print "@foos";  # prints 2 3 4

因此,当您在代码中更改$part时,数组@parts也会更改,并且变为这样(Data::Dumper输出):

$VAR1 = [
          '"John"',
          '"Smith"',
          '"jsmith@bogusaddress.net"',
          '"000-0000"'
        ];

从那时起,如果没有先删除引号,就无法将字符串"John""Smith"放在一起。

我还使用Text::CSV准备了一个解决方案,我看到ThisSuitIsBlackNot已经这样做了,所以你可以看一下his answer的实际解决方案。

对于更轻量级的解决方案,您可以使用Text::ParseWords。这与Text::CSV一样,具有处理引用分隔符的好处。

use Text::ParseWords;

my $line = 'John,Smith,jsmith@bogusaddress.net,000-0000';
my @parts = quotewords(",", 0, $line);
push @parts, "@parts[0,1]";
print join ",", map qq("$_"), @parts;

答案 1 :(得分:2)

在处理分隔数据时,我总是使用Text::CSV。它允许您轻松更改分隔符,引用行为和转义字符,并处理包含分隔符的字段,这很难自行处理(尽管这不适用于您的示例)。

以下内容将引用文件input.csv中的所有字段,并将结果写入STDOUT

#!/usr/bin/perl

use strict;
use warnings;

use Text::CSV;

my $csv = Text::CSV->new({
    binary => 1,
    auto_diag => 1,
    always_quote => 1,
    eol => $/
}) or die "Cannot use CSV: " . Text::CSV->error_diag;

open my $fh, '<', 'input.csv' or die "input.csv: $!";

while (my $row = $csv->getline($fh)) {
    $csv->print(\*STDOUT, $row);
}

close $fh;

input.csv

John,Smith,jsmith@bogusaddress.net,000-0000
Jane,Doe,jdoe@bogusaddress.net,000-0000

输出

"John","Smith","jsmith@bogusaddress.net","000-0000"
"Jane","Doe","jdoe@bogusaddress.net","000-0000"

答案 2 :(得分:0)

$part循环别名中

foreach @parts的每个元素。所以你实际上存储回数组,你用引号包装的字符串。

尝试使用Data::Dumper并在每个循环的底部转储@parts

use Data::Dumper;

...
print Dumper( \@parts );

答案 3 :(得分:0)

没有理由使用for循环将各个部分串在一起。如果您可以使用split,则可以使用join

my $line = "John,Smith,jsmith@bogusaddress.net,000-0000";
my @parts = split  /,/, $line;             # Split the line on commas
my $new_line = join q(","), @parts;        # Separate out the parts with quote-comma-quote
my $new_line = qq("$new_line");            # Add pre and post quotes

q(...)是一个quote-like运算符,用作单引号。 qq(...)是一个类似于引用的运算符,用作双引号。理解qq("$line")q(",")而不是"\"$line"\"'","'会更容易理解。

我使用加入与","加入所有部分。它处理$new_line中间的分隔,但不处理开始和结束引用。因此,我需要第二个命令行来添加前缀和后置引号。