我遇到了一个程序问题,该程序通过一个包含几百万条记录的CSV文件进行解析:每行中有两个字段包含用户输入的评论,有时他们在评论中使用逗号。如果有逗号输入,则该字段将包含在双引号中。我需要用空格替换在这些字段中找到的任何逗号。这是文件中的一个这样的一行,可以给你一个想法 -
1925,47365,2,650187016,1,1,"MADE FOR DRAWDOWNS, NEVER P/U",16,IFC 8112NP,Standalone-6,,,44,10/22/2015,91607,,B24W02651,,"PA-3, PURE",4/28/2015,1,0,,1,MAN,,CUST,,CUSTOM MATCH,0,TRUE,TRUE,O,C48A0D001EF449E3AB97F0B98C811B1B,POS.MISTINT.V0000.UP.Q,PROD_SMISA_BK,414D512050524F445F504F5331393235906F28561D2F0020,10/22/2015 9:29,10/22/2015 9:30
注意 - 我没有Text :: CSV模块,也没有在我正在使用的服务器上使用。
以下是我解析此文件的代码的一部分。我做的第一件事是连接前三个字段并将该连接字段添加到每一行。然后我想清除@fields [7,19]中的逗号,然后在三个字段中格式化DATE,在两个字段中格式化DATETIME。我唯一能解决的问题就是清除那些逗号 -
my @data;
# Read the lines one by one.
while ( $line = <$FH> ) {
# split the fields, concatenate the first three fields,
# and add it to the beginning of each line in the file
chomp($line);
my @fields = split(/,/, $line);
unshift @fields, join '_', @fields[0..2];
# remove user input commas in fields[7,19]
$_ = for fields[7,19];
# format DATE and DATETIME fields for MySQL/sqlbatch60
$_ = join '-', (split /\//)[2,0,1] for @fields[14,20,23];
$_ = Time::Piece->strptime($_,'%m/%d/%Y %H:%M')->strftime('%Y-%m-%d %H:%M') for @fields[38,39];
# write the parsed record back to the file
push @data, \@fields;
}
答案 0 :(得分:1)
如果只是 ONLY 第八个麻烦 AND 的字段你确切地知道应该有多少字段,你可以这样做
假设字段总数始终 N
,
,
重新加入剩余的内容。现在形成字段8 然后做你喜欢做的事情。例如,将其写入正确的 CSV文件
答案 1 :(得分:0)
Text::CSV_XS处理引用的逗号就好了:
var automationElements = AutomationElement.FromHandle(proc.MainWindowHandle);
// Find `New Tab` element
var propCondNewTab = new PropertyCondition(AutomationElement.NameProperty, "New Tab");
var elemNewTab = automationElements.FindFirst(TreeScope.Descendants, propCondNewTab);
// Get parent of `New Tab` element
var treeWalker = TreeWalker.ControlViewWalker;
var elemTabStrip = treeWalker.GetParent(elemNewTab);
// Loop through all tabs
var tabItemCondition = new PropertyCondition(AutomationElement.ControlTypeProperty, ControlType.TabItem);
foreach (AutomationElement tabItem in elemTabStrip.FindAll(TreeScope.Children, tabItemCondition)) {
var nameProperty = tabItem.GetCurrentPropertyValue(AutomationElement.NameProperty);
Debug.WriteLine("title: " + nameProperty.ToString());
}
答案 2 :(得分:0)
注意以下两个主要版本清理一个字段。该问题的最新变化表明事实上有两个这样的字段。可以修改代码,但我会先等待对此的反馈。 最后,第三个版本适用于任意数量的坏字段。所有代码都已使用提供的示例及其变体进行测试。
在澄清之后,这将处理需要手动处理文件的情况。很容易建议使用模块来解析.csv
,但这里存在一个问题:依赖用户输入双引号。如果他们最终没有在那里我们有一个格式错误的文件。
我认为文件中的字段数是确定的,并且是提前知道的。
下面的两个独立解决方案使用数组或字符串处理。
(1)无论如何都要逐行处理文件,该行已被拆分。如果字段多于预期,则按空格连接额外的数组元素,然后使用正确的字段覆盖数组。这类似于vanHoesel在答案中概述的内容。
use strict;
use warnings;
my $num_fields = 39; # what should be, using the example
my $ibad = 6; # index of the malformed field-to-be
my @last = (-($num_fields-$ibad-1)..-1); # index-range, rest of fields
my $file = "file.csv";
open my $fh, '<', $file;
while (my $line = <$fh>) { # chomp it if needed
my @fields = split ',', $line;
if (@fields != $num_fields) {
# join extra elements by space
my $fixed = join ' ', @fields[$ibad..$ibad+@fields-$num_fields];
# overwrite array by good fields
@fields = (@fields[0..$ibad-1], $fixed, @fields[@last]);
}
# Process @fields normally
print "@fields";
}
close $fh;
(2)预处理文件,仅检查格式错误的行并根据需要修复它们。使用字符串操作。 (或者,可以使用上述方法。)$num_fields
和$ibad
是相同的。
while (my $line = <$fh>) {
# Number of fields: commas + 1 (tr|,|| counts number of ",")
my $have_fields = $line =~ tr|,|| + 1;
if ($have_fields != $num_fields) {
# Get indices of commas delimiting the bad field
my ($beg, $end) = map {
my $p = '[^,]*,' x $_;
$line =~ /^$p/ and $+[0]-1;
} ($ibad, $ibad+$have_fields-$num_fields);
# Replace extra commas and overwrite that part of the string
my $bad_field = substr($line, $beg+1, $end-$beg-1);
(my $fixed = $bad_field) =~ tr/,/ /;
substr($line, $beg+1, $end-$beg-1) = $fixed;
}
# Perhaps write the line out, for a corrected .csv file
print $line;
}
在最后一行中,$line
的坏部分被分配给substr
,这个函数允许的内容被覆盖。新的子字符串$fixed
是使用逗号更改(或删除,如果需要)构造的,并用于覆盖$line
的坏部分。见文档。
如果已知引号,则可以使用正则表达式。 适用于任意数量的错误字段。
while (my $line = <$fh>) {
$line =~ s/."([^"]+)"/join ' ', split(',', $1)/eg; # "
# process the line. note that double quotes are removed
}
如果要保留引号,请将它们移到括号内,以便进行捕捉。
在 while (...) {
之后需要完成这一行,以清理数据。
/e
修饰符使得替换方被评估为代码,而不是用作双引号字符串。在那里,行的匹配部分("
之间)用逗号分隔,然后用空格连接,从而修复字段。请参阅perlretut
中“搜索并替换”下的最后一项。
所有代码都已在错误字段中使用多行和多个逗号进行测试。