使用 sed 在每行开头捕获不同长度的数字

使用 sed 在每行开头捕获不同长度的数字

我正在处理一个格式如下的文件:

12345:ABCDEFG

789:HIJK

4963158:LMNOPQRSTUV

每行以不同长度的数字开头,后跟一个冒号,然后是一串不同长度的字母。我想只捕获每行开头的数字并将它们放入一个新文件中,如下所示。

12345

789

4963158

这与我得到的最接近,但它仍然打印整行,而不仅仅是数字。

sed -r 's/([^0-9]+d)(:)([A-Z]+)$/\1/' example.txt >> justnumbers.txt

我在语法上做错了什么?

答案1

有时,以不同的方式看待问题可以得出更简单的答案。

您将其视为“我想保留 : 之前的所有数字”,这是完全合理的。另一种看待它的方式可能是“我想扔掉从 : 到结尾的所有内容”。

这导致

s/:.*//

作为 sed 命令。

例如

$ cat x
12345:ABCDEFG
789:HIJK
4963158:LMNOPQRSTUV

$ sed 's/:.*//' x
12345
789
4963158

答案2

如果要点是返回:每行第一行剩下的内容,那么只需执行以下操作:

<your-file cut -d: -f1

添加该-s选项将跳过不包含任何:.

:要返回由 1 个或多个 ASCII 数字后跟一个或多个 ASCII 大写字母组成的行中剩下的内容,并丢弃与:该模式不匹配的任何行,您可以使用sed// awkperl

<your-file sed -n '^\([0123456789]\{1,\}\):[ABCDEFGHIJKLMNOPQRSTUVWXYZ]\{1,\}$/\1/p'

或者:

<your-file LC_ALL=C sed -n 's/^\([0-9]\{1,\}\):[A-Z]\{1,\}$/\1/p'

C区域设置是唯一保证这些[0-9],[A-Z]范围等于第一个命令中的显式集的区域设置)。

或者,如果您sed支持扩展正则表达式-E的选项E(从 70 年代而不是 60 年代开始扩展,尽管sed实现直到 90 年代末才开始添加对它们的支持):

<your-file LC_ALL=C sed -nE 's/^([0-9]+):[A-Z]+$/\1/p'

或者使用perl(使用 80 年代的正则表达式):

<your-file perl -lne 'print $1 if /^(\d+):[A-Z]+$/'

pcregrep是一个grep使用perl类似正则表达式并支持-o<n>输出第一个n捕获组的实现:

<your-file pcregrep -xo1 '(\d+):[A-Z]+'

有些grep实现也有一个-o选项,但仅输出整个匹配,但有些支持-P使用类似 perl 的正则表达式,您可以使用环视运算符来检查内容,而不将它们包含在匹配中:

<your-file grep -Po '^(\d+)(?=:[A-Z]+$)'

它匹配行开头的 1 个或多个数字序列,前提是它后面跟着(?=...):1 个或多个[A-Z]s (在 perl 正则表达式中不区分区域设置,因此LC_ALL=C没有必要),然后是结尾的线。


公平地说,从那时起它们都在不断发展,特别是对于 Perl 而言。 70 年代末的 ERE 添加了+, ?and |(更重要的是一种用于匹配的新算法),但丢失了\x反向引用。\{min,max\}在 80 年代后期被添加到 BRE(因此可以执行与+和相同的操作?),{min,max}后来再次添加到 ERE,但并不总是如此,因为这破坏了向后兼容性。 POSIX 引入了一些[[:class:]], [[=x=]], [[.x.]](为了更好或更有价值)。 BRE/ERE 的某些实现都有非标准扩展,包括一些来自perl\d的扩展*?

答案3

尝试这个:

sed -E 's/([0-9]+):[A-Z]+/\1/' example.txt

-E相同-r,但现在更标准一些。

正则表达式中的问题是您在开头使用负括号表达式 ( [^0-9]),然后匹配文字d字符。

我还删除了额外的捕获组,因为不需要它们。

总的来说,非常努力!你们真的很亲密。这些是您在开始使用正则表达式时遇到的问题。

答案4

使用(以前称为 Perl_6)

~$ raku -pe 's/^ (\d+) \: .* $/$0/;'  file

#OR

~$ raku -pe 's/^ \d+ <( \: .* $//;'  file

如果您查看许多不同的正则表达式实现,它可以帮助您发现共同的主题。对于 Perl 和 Raku,-pe命令行标志提供sed类似行为,在每行上运行代码并自动打印。

上面的第一个 Raku 示例捕获^字符串开头\d+数字(一个或多个),后跟:冒号(反斜杠转义)和.*任何字符零次或多次,直到$字符串结尾(即线)。 Raku 捕获从 开始$0,捕获到的数字$0用于替换一半 来s///替换整个匹配对象(即整行)。

上面的第二个 Raku 示例采用相反的方法:它匹配^字符串开头\d+数字(一个或多个),后跟:冒号(反斜杠转义)和.*任何字符零次或多次,直到$字符串结尾(即行)。然而,<(“捕获标记”告诉 Raku 的正则表达式引擎从匹配对象中删除前面的\d+数字,只保留后面的数字。在替换中,匹配对象中剩余的所有内容都将被删除(替换为任何内容),因此仅\d+保留字符串开头的数字。

https://docs.raku.org/language/regexes#Capture_markers:_%3C(_)%3E
https://docs.raku.org/language/regexes
https://raku.org

相关内容