【发布时间】:2011-06-07 02:07:05
【问题描述】:
我有一个巨大的文件,作为输出,一些列没有值,我需要用 0 填充这些列以进行进一步分析。我可以用空格或制表符分隔列,现在可以看到下面用制表符分隔。
【问题讨论】:
-
只是一个问题,您检查过编辑器中的最后一个空白列吗?列数据(不是分隔符)是实际的 \t 吗?
我有一个巨大的文件,作为输出,一些列没有值,我需要用 0 填充这些列以进行进一步分析。我可以用空格或制表符分隔列,现在可以看到下面用制表符分隔。
【问题讨论】:
这确实是 CSV 解析器的工作,但如果它必须是正则表达式,并且您在引用的 CSV 条目中从来没有标签,您可以搜索
(^|\t)(?=\t|$)
替换为
$10
所以,在 Perl 中:
(ResultString = $subject) =~
s/( # Match either...
^ # the start of the line (preferably)
| # or
\t # a tab character
) # remember the match in backreference no. 1
(?= # Then assert that the next character is either
\t # a(nother) tab character
| # or
$ # the end of the line
) # End of lookahead assertion
/${1}0/xg;
这将改变
1 2 4 7 8
2 3 5 6 7
进入
1 2 0 4 0 0 7 8
0 2 3 0 5 6 7 0
【讨论】:
对于制表符分隔的文件,这个 AWK sn-p 可以解决问题:
BEGIN { FS = "\t"; OFS="\t" }
{
for(i = 1; i <= NF; i++) {
if(!$i) { $i = 0 }
}
print $0
}
【讨论】:
$0 是多余的:print 就足够了。
这是sed 解决方案。请注意,sed 的某些版本不喜欢\t。
sed 's/^\t/0\t/;:a;s/\t\t/\t0\t/g;ta;s/\t$/\t0/' inputfile
或
sed -e 's/^\t/0\t/' -e ':a' -e 's/\t\t/\t0\t/g' -e 'ta' -e 's/\t$/\t0/' inputfile
解释:
s/^\t/0\t/ # insert a zero before a tab that begins a line
:a # top of the loop
s/\t\t/\t0\t/g # insert a zero between a pair of tabs
ta # if a substitution was made, branch to the top of the loop
s/\t$/\t0/ # insert a zero after a tab that ends a line
【讨论】:
a\t\t\tb 的情况,则需要一个循环。正则表达式匹配永远不会重叠。因此,如果循环不可用,a\t\t\tb 将更改为a\t0\t\tb 而不是a\t0\t0\tb
重新阅读原帖后删除我的答案。没有标签作为数据,只有分隔符。如果没有数据,将出现一个双分隔符来对齐列。
不可能是其他方式。因此,如果存在单个分隔符,它将分隔两个空字段。 "" = 1 个空字段,"\t" = 2 个空字段。我现在明白了。
Tim Pietzcker 一直都有正确的答案。为他 +1。
也可以写成s/ (?:^|(?<=\t)) (?=\t|$) /0/xg;,但都是一样的。
【讨论】:
s!(?:^|(?<=\t))\t!$number\t!g。或者您可以将 1 个衬垫作为批处理参数。不知道你在做什么。
perl -pe 's/(?:^|(?<=\t))(?:(?=\t$)\t|(\t))/0$1/g' d.txt
当且仅当您的数据仅包含数字并且您有明确定义的字段分隔符FS,您可以使用以下技巧:
awk 'BEGIN{FS=OFS="\t"}{for(i=1;i<=NF;++i) $i+=0}1' file
通过添加零,我们将字符串转换为数字。空字符串将被转换为数字零。您可以将字段分隔符定义为您喜欢的任何内容。
但是,这可能会有点慢,因为每次重新分配字段 $i 时,它都会重新解析 $0 并将其拆分为字段。
更快的方法是Dennis Williamson的解决方案
【讨论】: