18

我有一个文件,里面有电话号码数据,还有一些没用的东西。我正在尝试解析数字,当只有 1 个电话号码/线路时,这不是问题。但是当我有多个数字时, sed 匹配最后一个(即使它说它应该只匹配第一个模式?),我无法得到其他数字..

我的数据.txt:

bla bla bla NUM:09011111111 bla bla bla bla NUM:08022222222 bla bla bla

当我解析数据时,我的想法是首先删除第一个电话号码前面的所有“初始”“bla bla bla”(所以我搜索第一次出现的“NUM:”),然后删除所有的东西在电话号码之后,并获取号码。之后,我想从剩余的字符串中解析下一个匹配项。

所以现在当我尝试 sed 它时,我总是得到最后一个数字:

>sed 's/.*NUM://' data.txt
08022222222 bla bla bla
> 

首先,我想了解我对 SED 的理解有什么问题。当然欢迎更有效的建议!我的 sed 命令不是说,用 ''(空)替换 'NUM:' 之前的所有内容吗?为什么它总是匹配最后一次出现?

谢谢!

4

5 回答 5

25

这可能对您有用:

echo "bla bla bla NUM:09011111111 bla bla bla bla NUM:08022222222 bla bla bla" |
sed 's/NUM:/\n&/g;s/[^\n]*\n\(NUM:[0-9]*\)[^\n]*/\1 /g;s/.$//'
NUM:09011111111 NUM:08022222222

您遇到的问题是理解它.*是贪婪的,即它匹配最长的匹配而不是第一个匹配。通过在我们感兴趣的字符串前面放置一个唯一字符(\nsed 将其用作行分隔符,因此它不能存在于行中) ( NUM:...) 并删除所有不是唯一字符的所有内容,[^\n]*然后是唯一字符\n,我们有效地将字符串拆分为可管理的部分。

于 2012-03-13T10:02:02.123 回答
12

正如你现在所知道的,正sed则表达式是贪婪的,据我所知,不能让它变得不贪婪。

直到现在还没有提出的两种替代方法是仅使用其他工具进行这种匹配/提取。

您可以使用参数perl替代 sed -pe。它支持?非贪婪修饰符:

$ perl -pe 's/.*?NUM://' data.txt
09011111111 bla bla bla bla NUM:08022222222 bla bla bla

您可以使用-oGNU grep 选项来仅获取与正则表达式匹配的数据位:

$ egrep -o 'NUM:[0-9]*' data.txt 
NUM:09011111111
NUM:08022222222
于 2012-03-13T11:35:20.030 回答
3

如果数字由 a 后面的数字定义NUM:

sed -n -e 's/$/\n/' -e ':begin' \
  -e 's/\(NUM:[0-9][0-9]*\)\(.*\)\n\(.*\)/\2\n\3 \1/' \
  -e 'tbegin' -e 's/.*\n //' -e '/NUM/p'

这是做什么的:

  1. 在行尾放置一个\n作为标记。
  2. 尝试在标记之前找到一个数字,并将其放在行尾(标记之后)。
  3. 如果找到数字,请转到上面的 2。
  4. 当标记前没有数字时,删除数字前的所有内容。
  5. 如果数字在行,则打印它(以处理找不到数字的情况。

也可以反过来做,首先删除没有数字的行:

sed  -e '/NUM/!d' -e 's/$/\n/' -e ':begin' \
  -e 's/\(NUM:[0-9][0-9]*\)\(.*\)\n\(.*\)/\2\n\3 \1/' \
  -e 'tbegin' -e 's/.*\n //'
于 2012-03-13T23:01:00.527 回答
0

您可以使用此模式:

sed -r 's/^(.*NUM:)(.*NUM:.*)$/\2/'
于 2012-03-13T09:47:41.907 回答
0
sed -E 's/(-y)|(-f)|(\+incdir\+)/\n&/g' abcfile > cdeop

其中 abcfile 将以 -y / -f / +incdir+ 模式为例,当模式匹配时,它将在其前面插入新行。

于 2021-02-10T07:20:02.443 回答