Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/regex/18.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Regex SED:同一行上有多个模式,如何匹配/解析第一个模式_Regex_Parsing_Sed_Last Occurrence - Fatal编程技术网

Regex SED:同一行上有多个模式,如何匹配/解析第一个模式

Regex SED:同一行上有多个模式,如何匹配/解析第一个模式,regex,parsing,sed,last-occurrence,Regex,Parsing,Sed,Last Occurrence,我有一个文件,里面有电话号码数据,还有一些无用的东西。 我正在尝试解析这些号码,当每行只有一个电话号码时,这不是问题。 但是当我有多个数字时,sed会匹配最后一个数字(即使它说它应该匹配的地方只匹配第一个模式?),而我无法得到其他数字 My data.txt: bla bla bla NUM:09011111111 bla bla bla bla NUM:08022222222 bla bla bla 当我解析数据时,我的想法是首先删除第一个电话号码前面的所有“初始”“bla bla bla”

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

My data.txt:

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

因此,现在当我尝试使用它时,我总是得到最后一个号码:

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


谢谢

您可以使用此模式:

sed -r 's/^(.*NUM:)(.*NUM:.*)$/\2/'

这可能适合您:

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

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

正如您现在所知,
sed
正则表达式是贪婪的,据我所知,不能使其成为非贪婪的

到目前为止还没有提出的两个备选方案是仅使用其他工具进行这种匹配/提取

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

$ perl -pe 's/.*?NUM://' data.txt
09011111111 bla bla bla bla NUM:08022222222 bla bla bla
您可以使用GNU grep的
-o
选项仅获取与正则表达式匹配的数据位:

$ egrep -o 'NUM:[0-9]*' data.txt 
NUM:09011111111
NUM:08022222222

如果数字是由
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'
它的作用是:

  • 在行尾放置一个
    \n
    作为标记
  • 试着在标记之前找到一个数字,并将其放在行的末尾(标记之后)
  • 如果找到号码,请转到上面的2
  • 如果标记前没有数字,请删除数字前的所有内容
  • 如果线上有一个号码,请打印它(以处理找不到号码的情况)
  • 也可以采用另一种方法,首先删除不带编号的行:

    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 //'
    

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

    Sed是贪婪的。如果有第二个NUM:,第一个NUM可由
    *
    +1使用,用于示例数据、隐含的预期输出和一些不起作用的示例代码。祝您好运。感谢您建议al或者,我一定会研究sed和perlThanks之间可能存在的性能差异,以获得egrep建议。糟糕的是,sed将自己限制在占用整行的模式空间。我怀疑这确实与贪婪有关。哇,这回答了我花数小时搜索基于字符而不是基于行的示例的问题-基于sed的工作。我看到我们将换行符作为标记粘贴在基于行的模式空间中,然后删除以该标记结尾的部分以对抗sed的贪婪匹配。OSX:“\n”不适用于sed。请使用“gsed”(可通过Brew安装)相反,我很感谢您抽出时间给我一个替代解决方案,我会研究它。但是,这似乎有点难以理解,而且这里有相当多的sed调用,我担心性能比“三调用解决方案”慢有一个对sed的调用,只有一个更复杂的脚本,包含6个命令。没错,Poton的解决方案只有3个命令,但是这些命令执行了不止一次(
    g
    参数指向
    s
    命令),所以这并不意味着它更快。我同意它对于这个问题更优雅一点。
    sed -E 's/(-y)|(-f)|(\+incdir\+)/\n&/g' abcfile > cdeop