Arrays 数组中的串联字符串变量在Perl中给出了意外的引号
我有一个CSV文件,我需要用引号将每个值括起来,其中每个值都是一个字符串。连接时,我得到了意外的引号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
$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;