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 组,带制表符分隔符
因此,您可以每行提取两个单独的字段,只是用制表符分隔,以便以后更容易操作。
输入:-
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 组,带制表符分隔符
因此,您可以每行提取两个单独的字段,只是用制表符分隔,以便以后更容易操作。