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

mar*_*ssa 6 sed

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

12345:ABCDEFG

789:HIJK

4963158:LMNOPQRSTUV
Run Code Online (Sandbox Code Playgroud)

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

12345

789

4963158
Run Code Online (Sandbox Code Playgroud)

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

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

我在语法上做错了什么?

Ste*_*ris 10

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

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

这导致

s/:.*//
Run Code Online (Sandbox Code Playgroud)

作为 sed 命令。

例如

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

$ sed 's/:.*//' x
12345
789
4963158
Run Code Online (Sandbox Code Playgroud)

  • 这就像“cut -d: -f1”,尽管面对未根据用户区域设置进行编码的文本时不太可靠。 (2认同)

Sté*_*las 6

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

\n
<your-file cut -d: -f1\n
Run Code Online (Sandbox Code Playgroud)\n

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

\n

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

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

或者:

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

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

\n

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

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

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

\n
<your-file perl -lne 'print $1 if /^(\\d+):[A-Z]+$/'\n
Run Code Online (Sandbox Code Playgroud)\n

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

\n
<your-file pcregrep -xo1 '(\\d+):[A-Z]+'\n
Run Code Online (Sandbox Code Playgroud)\n

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

\n
<your-file grep -Po '^(\\d+)(?=:[A-Z]+$)'\n
Run Code Online (Sandbox Code Playgroud)\n

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

\n
\n

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

\n


Seb*_*los 5

尝试这个:

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

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

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

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

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

  • `^` 不是*负捕获组*,它是为了在主题的开头匹配。这里需要它。如果您还删除了“$”(以匹配主题末尾),则第二个“+”就变得不必要了。实际上,该代码返回一个或多个数字的第一个序列(0 到 9 之间的字符,根据区域设置可以是任何字符),后跟“:”以及“A”和“Z”之间的字符。 (3认同)
  • OP regexp 的第一个捕获组是 `([^0-9]+d)`。在字符类括号内“^” _is_ 否定该组,因此将匹配除数字之外的任何内容。但是,是的,它不应该被删除,它应该被移动到方括号“^([0-9]+)”之外,这样它就意味着行的开始。 (2认同)