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

Arrays 数组中的串联字符串变量在Perl中给出了意外的引号,arrays,string,perl,concatenation,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 = $par

我有一个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""
为什么我会得到额外的报价


谢谢您的帮助。

foreach
循环中的
$part
@parts
的每个元素添加了别名。实际上,您正在将用引号包装的字符串存储回数组中

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

use Data::Dumper;

...
print Dumper( \@parts );
我在处理分隔数据时始终使用。它允许您轻松地更改分隔符、引用行为和转义字符,并处理包含分隔符的字段,这很难单独处理(尽管这不适用于您的示例)

下面将引用文件
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;
输出


没有理由使用
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(…)
是一个用作单引号的运算符。
qq(…)
是一个类似引号的操作符,充当双引号。相比于
“\“$line”\”
“,”
,理解
qq(“$line”)
q(“,”
)更容易一些


我正在使用join将所有部分与
,“
连接起来。在“代码”的中间处理分离,$NexyLoe< /Cord>,但不处理开始和结束引用。因此,我需要第二个命令行来添加前引号和后引号。

已经提供了很多实用的解决方案,但是我想回答您的问题:为什么会发生这种情况

您获得双引号的原因是您实际上正在更改
@parts
的元素。在
for
循环中,元素被别名化为循环参数,因此对它们的任何更改都直接对“实”值进行。考虑以下事项:

my @foos = 1 .. 3;
for my $foo (@foos) {
    $foo += 1;
}
print "@foos";  # prints 2 3 4
因此,当您在代码中更改
$part
时,数组
@parts
也会更改,并变成这样(
Data::Dumper
output):

从那时起,如果不再次删除引号,就不能将字符串
“John”
“Smith”
组合在一起

我还使用
Text::CSV
准备了一个解决方案,我看到已经这样做了,所以您可以查看一个实用的解决方案

对于更轻量级的解决方案,您可以使用
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;

你是5的最新版本吗?5.16或5.18?这不是您的实际代码,因为如果是,
@bogusaddress
将被插入为数组。我使用5.16.3表示歉意。我在一个文件里有真实的数据。我用一句话来回答这个问题。在最后一刻,我决定把它做成假数据。我这样做时被打断了。读取文件中的行在电子邮件地址中有@(没有转义),并且处理得很好(没有解释为数组)。谢谢大家的帮助。我可能应该解释我是一名电子设计师。在70年代学习了Fortran IV。我们只有Perl的基本介绍。因此,代码过于复杂和冗长。我不知道在许多解决方案中讨论的优雅方式。谢谢你的帮助和耐心@TLP,“阵列”被插值掉。OP显然没有开启警告。这就是他得到“jsmith.net”的原因。
my @foos = 1 .. 3;
for my $foo (@foos) {
    $foo += 1;
}
print "@foos";  # prints 2 3 4
$VAR1 = [
          '"John"',
          '"Smith"',
          '"jsmith@bogusaddress.net"',
          '"000-0000"'
        ];
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;