Unix 中的动态分隔符

Dynamic delimiter in Unix

输入:-

echo "1234ABC89,234"      # A
echo "0520001DEF78,66"    # B
echo "46545455KRJ21,00"

从上面的字符串中,我需要拆分字符以获得字母字段和后面的数字。

"1234ABC89,234"开始,输出应该是:

ABC
89,234

"0520001DEF78,66"开始,输出应该是:

DEF
78,66

我有很多字符串需要像这样拆分。

到目前为止,这是我的脚本:

echo "1234ABC89,234" | cut -d',' -f1

但它给了我 1234ABC89 这不是我想要的。

假设您只想丢弃前导数字,并且字母全部大写,那么以下应该可行:

echo "1234ABC89,234" | sed 's/^[0-9]*\([A-Z]*\)\([0-9].*\)/\n/'

这适用于 GNU sed(我有 4.2.2),但其他 sed 实现可能不喜欢 \n,在这种情况下,您需要替换其他东西。

根据 sed 的版本,您可以尝试:

echo "0520001DEF78,66" | sed -E -e 's/[0-9]*([A-Z]*)([,0-9]*)/\n/'

或:

echo "0520001DEF78,66" | sed -E -e 's/[0-9]*([A-Z]*)([,0-9]*)/$/' | tr '$' '\n'

DEF
78,66

说明:正则表达式将输入替换为预期的输出,除了 new-line 它放置了一个“$”符号,我们用 tr 命令将其替换为 new-line

字符串从哪里来?它们是从文件(或脚本外部的其他来源)中读取的,还是存储在脚本中的?如果它们在脚本中,您应该简单地重新格式化数据以便于管理。因此,明智的做法是假设它们来自外部数据源(例如文件)或通过管道传输到脚本。

您可以简单地通过 sed:

提供数据
sed 's/^[0-9]*\([A-Z]*\)/ /' |
while read alpha number
do
    …process the two fields…
done

唯一需要注意的技巧是,如果您在循环中设置变量,它们不一定对 done 之后的脚本可见。有很多方法可以解决这个问题——其中一些取决于您使用的 shell。这在 Bourne shell.

的任何衍生作品中都是相同的

你说你有很多这样的字符串,所以我建议尽可能将它们保存到文件中,例如 input.txt:

1234ABC89,234
0520001DEF78,66
46545455KRJ21,00

在你的命令行上,试试这个 sed 命令读取 input.txt 作为文件参数:

$ sed -E 's/([0-9]+)([[:alpha:]]{3})(.+)/\t/g' input.txt
ABC     89,234
DEF     78,66
KRJ     21,00

工作原理

  • 使用 -E 扩展正则表达式以节省输入,否则例如对于分组我们将不得不转义 \(
  • 使用分组 (),搜索三个组:
  • 第一个数字,+指定one-or-more个数字。奇怪的是,使用 [0-9] 会在结果上方多出一个空白 space,因此请使用 POSIX class [[:digit:]]
  • 接下来是搜索POSIX个字母字符,不管是小写还是大写,{3}指定搜索其中的3个
  • 最后一组搜索.表示任意字符,+一次或多次
  • \t 然后 returns 第 2 组和第 3 组,带制表符分隔符

因此,您可以每行提取两个单独的字段,只是用制表符分隔,以便以后更容易操作。