正则表达式:使用 AWK gsub 的异常模式

Regular Expression: PATTERN with exception using AWK gsub

我有一个数据文件(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

此数据中只有 space,但没有标签。

我想将所有 space(s) 替换为“:”,但保留 space 的国家/地区名称不变。

也就是说,我想要的输出应该如下所示:

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", [=14=]) }' cou.data | sed -r 's/ +/:/g; s/~/ /g'

您需要捕获组和反向引用,并非所有 awk 实现都支持它。GNU awk 使用 gensub 支持它。我建议使用 sed 而不是

$ sed -E 's/ +([0-9])/:/g; s/([0-9]) +/:/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
  • -E 启用 ERE,某些 sed 版本需要 -r 而不是 -E
  • s/ +([0-9])/:/g 匹配一个或多个空格后跟一个数字。我们只需要替换空格,但保留数字不变。所以捕获数字并使用反向引用在替换部分引用它
  • s/([0-9]) +/:/g 这将涵盖数字后跟空格的情况
  • 通过将正则表达式放在 () 中来定义捕获组 - 从左到右,</code> 指第一个这样的组,<code> 指第二个这样的组,依此类推


使用 perl,您可以避免使用捕获组

perl -pe 's/ +(?=\d)|\d\K +/:/g' ip.txt

+(?=\d)|\d\K + 仅在后面跟有数字或前面有数字时才匹配空格


使用 GNU awk,请参阅 gawk String-Manipulation Functions 了解语法和详细信息

awk '{[=12=]=gensub(/ +([0-9])/, ":\1", "g", [=12=]);
      print gensub(/([0-9]) +/, "\1:", "g", [=12=])}' ip.txt 

您可以使用反向引用来包含您希望在 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