正则表达式:使用 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
我有一个数据文件(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