我有500个大小混乱的数据集(.csv)的列表,如下所示:
0.00, 0.53, 1.53, 0.00 0.52, 243.21
... etc etc.
我想:
0.00, 0.53, 1.53, 0.00, 0.52, 243.21
在perl(或bash)中,我如何匹配小数点后的所有内容,如果有空格后跟另一个数字,那么我会插入一个逗号在第一个号码之后?
即。 0.00 0.52
进入0.00, 0.52
我是perl和编程的初学者,所以我不太了解如何正确使用它。
我发现正则表达式[0-9]+(\.[0-9][0-9]?)?
应该适用于两位小数,但是更多的小数呢?只是[0-9]+(\.[0-9]+?)?
我未成功的尝试:
for my $file (glob '*.csv') {
open my $in, '<', $file;
my @lines;
while (<$in>) {
while(/^[0-9]+(\.[0-9]+)?$/g){
print ","; # Am I overwritting my lines here?
}
$line =~ s/,,/,/g; # Get rid of any double commas that appear now
}
close $in;
open my $out, '>', $file;
print $out $_ for @lines;
close $out;
}
我认为我没有正确匹配/打印 - 感谢任何帮助,包括更优雅的解决方案。
提前谢谢!
答案 0 :(得分:2)
去懒惰:
#!/usr/bin/env perl
use strict;
use warnings;
while ( <DATA> ) {
print join ( ", ", m/([\d\.]+)/g );
}
__DATA__
0.00, 0.53, 1.53, 0.00 0.52, 243.21
输出:
0.00, 0.53, 1.53, 0.00, 0.52, 243.21
这适用于:
join
未插入
尾随分隔符。所以要拿你的代码:
#!/usr/bin/env perl
use strict;
use warnings;
for my $file (glob '*.csv') {
open my $in, '<', $file or die $!;
open my $out, '>', "$file.new" or die $!;
while (<$in>) {
print {$out} join ( ", ", m/([\d\.]+)/g );
}
}
这是有效的,因为while
循环的每次迭代都会自动将隐式变量$_
设置为“当前行”。默认情况下,m
和s
正则表达式(以及一堆其他perl函数)会在$_
上运行。
所以你可以把它重写为:
while ( my $line = <$in> ) {
my @stuff = $line =~ m/([\d\.]+)/g;
print {$out} join ( ",", @stuff );
}
隐式变量对某些东西很好,但要警惕它们 - 只有在它们使代码更清晰时才使用它们。
要回答您的内联查询:
我在这里覆盖我的台词吗?
不 - print ","
正在写STDOUT。这根本不会改变你的档案。 (但它实际上也没有做任何有用的事情)。
您必须使用s
模式搜索/替换$_
- 当前行 - 然后push
进入@lines
。
我认为你在这里误解了几个基本概念:
@lines
与$line
无关。您实际上并没有对@lines
执行任何操作,因此在打印时它将为空。 while
和print
循环 - 没有做任何事情。 m
正则表达式 适用于$_
,它由while循环隐式设置为“当前行”。但你实际上没有改变这个值。 $line =~
...转换$line
。但$line
不存在,所以没有任何反应。 你真的应该在程序的开头添加use strict;
和use warnings
,因为你会被警告这些事情。
答案 1 :(得分:0)
我不会说perl,但原则上说:
Search: (?<=\.\d\d)(?= \d)
Replace: ,
答案 2 :(得分:0)
如果你可以安装Tie :: File,你可以这样做:
use strict;
use warnings;
use Tie::File;
for my $file (glob '*.csv') {
tie my @file, 'Tie::File', $file or die $!;
s/(\d)(\s+\d)/$1,$2/g foreach (@file);
untie @file;
}
请注意,这将修改原始文件。 Tie :: File将文件读入数组并允许您修改数据。