正则表达式:使用AWK gsub的PATTERN,但有例外

时间:2018-08-06 07:25:35

标签: regex awk gsub string-substitution

我有一个数据文件(cou.data)

USSR    8649    275 Asia
Cananda 3852    25  North America
China   3705    1032    Asia
USA 3615    237 North America
Brazil  3286    134 South America
India   1267    746 Asia
Mexico  762 78  North America
France  211 55  Europe
Japan   144 120 Asia
Germany 96  61  Europe
England 94  56  Europe
Taiwan  55  144 Asia
North Korea 44  2134    Asia

此数据中只有空格,没有制表符。

我想用“:”替换所有空格,但国名的空格保持不变。

也就是说,我所需的输出应如下所示:

USSR:8649:275:Asia
Cananda:3852:25:North America
China:3705:1032:Asia
USA:3615:237:North America
Brazil:3286:134:South America
India:1267:746:Asia
Mexico:762:78:North America
France:211:55:Europe
Japan:144:120:Asia
Germany:96:61:Europe
England:94:56:Europe
Taiwan:55:144:Asia
North Korea:44:2134:Asia

我已经动了脑筋,只能写这个

awk '{ gsub(/([a-zA-Z] +[0-9]|[0-9] +[a-zA-Z]|[0-9] +[0-9])/, ":"); print }' cou.data

但是输出不正确。

USS:64:7:sia
Canand:85::orth America
Chin:70:03:sia
US:61:3:orth America
Brazi:28:3:outh America
Indi:26:4:sia
Mexic:6::orth America
Franc:1::urope
Japa:4:2:sia
German:::urope
Englan:::urope
Taiwa::4:sia
North Kore::13:sia

一些不应该删除的零件不见了。

如何修改我的AWK代码,或者有一种简单的解决方案来获得我想要的?

ps

awk '{ print gensub(/([a-zA-Z])( )([a-zA-Z])/, "\\1~\\3", "g", $0) }' cou.data | sed -r 's/ +/:/g; s/~/ /g'

2 个答案:

答案 0 :(得分:3)

您需要捕获组和反向引用,并非所有awk实现都支持。GNU awk使用gensub支持它。我建议使用{{1} }代替

sed
  • $ sed -E 's/ +([0-9])/:\1/g; s/([0-9]) +/\1:/g' ip.txt USSR:8649:275:Asia Cananda:3852:25:North America China:3705:1032:Asia USA:3615:237:North America Brazil:3286:134:South America India:1267:746:Asia Mexico:762:78:North America France:211:55:Europe Japan:144:120:Asia Germany:96:61:Europe England:94:56:Europe Taiwan:55:144:Asia North Korea:44:2134:Asia 启用ERE,某些sed版本需要-E而不是-r
  • -E匹配一个或多个空格,后跟一个数字。我们只需要替换空格,但保持数字不变。因此,捕获数字并使用反向引用在替换部分中引用它
  • s/ +([0-9])/:\1/g将涵盖数字后跟空格的情况
  • 捕获组是通过将正则表达式放在s/([0-9]) +/\1:/g内来定义的-从左到右,()指的是此类组,\1指的是第二组,依此类推


使用\2,您可以避免使用捕获组

perl

perl -pe 's/ +(?=\d)|\d\K +/:/g' ip.txt 仅在空格后跟数字或数字前匹配空格


使用 +(?=\d)|\d\K +,请参见gawk String-Manipulation Functions了解语法和详细信息

GNU awk

答案 1 :(得分:2)

您可以使用反向引用来包含要与gnu awk一起保留的原始文档的部分。使用gensub并将反向引用添加到正则表达式中将为您提供以下内容。

gawk '{ print gensub(/(([a-zA-Z]) +([0-9]))|(([0-9]) +([a-zA-Z]))|(([0-9]) +([0-9]))/, "\\2\\5\\8:\\3\\6\\9", "g"); }' file

请参阅https://www.gnu.org/software/gawk/manual/gawk.html#index-substitute-in-string