如何使用sed或awk用空格替换管道,但只能在字母词之间

时间:2014-04-05 19:40:22

标签: bash sed awk

我一直在努力学习剧本。我有一份体操队和比分列表。我设法得到文件管道分隔,就像下面的小数据示例。但是,现在我需要用空格替换管道,但只有在字母词之间。数字之间的管道必须保留。这样,我可以拥有团队名称,无论有多少单词构成,都可以作为一个领域。然后,数据就可以加载到我的数据库中了。我知道sedawk使用正则表达式应该可以做到这一点,但我并不接近搞清楚。我整天搞砸了这一天,我相信有人可以在2分钟内告诉我如何做到这一点。 : - )

开始格式:

Twistars|28.250|28.700|28.100|27.950|113.600
Excel|Gymnastics|28.250|28.700|28.100|27.950|113.600
Head|Over|Heels|Gymnastics|28.250|28.700|28.100|27.950|113.600

我的最终目标:

Twistars|28.250|28.700|28.100|27.950|113.600
Excel Gymnastics|28.250|28.700|28.100|27.950|113.600
Head Over Heels Gymnastics|28.250|28.700|28.100|27.950|113.600

任何建议/小例子都会受到赞赏。

6 个答案:

答案 0 :(得分:2)

以下是awk解决方案:

awk -F\| '{printf $1;for (i=2;i<=NF;i++) printf (($(i-1)!~/[0-9.]+/ && $(i)!~/[0-9.]+/)?" ":"|")"%s",$i;print ""}' file
Twistars|28.250|28.700|28.100|27.950|113.600
Excel Gymnastics|28.250|28.700|28.100|27.950|113.600
Head Over Heels Gymnastics|28.250|28.700|28.100|27.950|113.600

答案 1 :(得分:2)

这可能适合你(GNU sed):

sed -r ':a;s/([[:alpha:]])\|([[:alpha:]])/\1 \2/g;ta' file

这将用空格替换单词之间的|。第二次扫描捕获第一次传球中错过的任何比赛。

答案 2 :(得分:1)

sed 's/\([[:alpha:]]\)|\([[:alpha:]]\)/\1 \2/g'  file
Twistars|28.250|28.700|28.100|27.950|113.600
Excel Gymnastics|28.250|28.700|28.100|27.950|113.600
Head Over Heels Gymnastics|28.250|28.700|28.100|27.950|113.600

答案 3 :(得分:1)

假设不应该加入最后5个字段:

awk '{p=$0; for(i=1;i<=NF-6;i++) sub(FS,OFS,p); print p}' FS='\\|' file

答案 4 :(得分:0)

echo 'Excel|Gymnastics|28.250|28.700|28.100|27.950|113.600' | sed 's/\([A-Za-z]\)\|\([A-Za-z]\)/\1 \2/g'

以上

的输出
Excel Gymnastics|28.250|28.700|28.100|27.950|113.600

以上显示了您需要的基本sed表达式。 你可以通过几种不同的方式进行修饰。

cat file | sed 's/\([A-Za-z]\)\|\([A-Za-z]\)/\1 \2/g' > newFile

sed 's/\([A-Za-z]\)\|\([A-Za-z]\)/\1 \2/g' file > newfile

您甚至可以使用某些版本的sed使用“就地编辑”标记 - 这意味着您将把文件写回到同一个地方:

sed -i 's/\([A-Za-z]\)\|\([A-Za-z]\)/\1 \2/g' file

说明:

\([A-Za-z]\)  capturing group: any character A-Z or a-z
\|            escaped pipe symbol (otherwise it means "or")
\([A-Za-z]\)  second capturing group: any character A-Z or a-z

我们用

替换上面的内容
\1 \2         first captured group, space, second captured group

/g            global flag: do it for all occurrences

答案 5 :(得分:0)

sed -e 's/\([[:alpha:]]\)|\([[:alpha:]]\)/\1 \2/g'

除了单个字母导致问题这一事实外,效果很好:

$ echo 'Tete|A|Tete|4.489' | sed -e 's/\([[:alpha:]]\)|\([[:alpha:]]\)/\1 \2/g'
Tete A|Tete|4.489

这可能使得awk成为更好的解决方案,尽管它更加冗长。

由于您已有文件,因此可以使用ex:

printf '%%s/\\([[:alpha:]]\\)|\\([[:alpha:]]\\)/\\1 \\2/g\n%%&g\n%%p\n' | ex -s file >file2

假设您正在使用支持here-documents的shell,您可以使其更具可读性,如下所示:

ex -s file >file2 <<EOF
%s/\([[:alpha:]]\)|\([[:alpha:]]\)/\1 \2/g
%&g
%p
EOF

它只是执行与sed一样的替换,除了它允许你使用&amp;重复它。命令。如果您希望它只是就地修改文件,请删除>file2并将%p更改为w

ex -s file <<EOF
%s/\([[:alpha:]]\)|\([[:alpha:]]\)/\1 \2/g
%&g
w
EOF

应该有&#34; sed for ex&#34;这使得ex的功能可用于管道输入,就像sed对ed一样,但我知道当前没有这样的实现。 Emacs附带一个手册,表明存在这样的实用程序,但该命令不可用,并且根据联机帮助页不会执行ex ..