我正在处理一个格式如下的文件:
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
// awk
:perl
<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