正则表达式:查找元素而不受顺序

时间:2019-07-01 10:37:33

标签: regex sed

如果我有字符串:

  

geo:FR,主机:www.example.com

(实际上,字符串更复杂,并且具有更多字段。)

我想提取“ geo”值和“ host”值,当键的顺序更改时,我面临一个问题,如下所示:

  

host:www.example.com,geo:FR

我尝试了这一行:

sed 's/.\*geo:\([^ ]*\).\*host:\([^ ]*\).*/\1,\2/'

但是它仅适用于第一个字符串。 有没有办法在单个正则表达式中做到这一点,如果没有,最好的方法是什么?

3 个答案:

答案 0 :(得分:2)

我建议使用单独的sed命令提取所需的每个文本:

s="geo:FR, host:www.example.com"
host="$(sed -n 's/.*host:\([^[:space:],]*\).*/\1/p'  <<< "$s")"
geo="$(sed -n 's/.*geo:\([^[:space:],]*\).*/\1/p'  <<< "$s")"

请参见online demoecho "$host and $geo"印刷品

www.example.com and FR

两个输入。

详细信息

  • -n禁止行输出,p打印匹配项
  • .*-将最后的0个字符与最后一个字符匹配...
  • host:-host:子字符串,然后
  • \([^[:space:],]*\)-将除空格和逗号以外的任何0个或多个字符捕获到第1组中
  • .*-该行的其余部分。

结果仅是第1组的内容(请参见替换模式中的\1)。

答案 1 :(得分:2)

每当您在输入中包含标记/名称/值对时,我都会发现最好(最清晰,最简单,最可靠,最容易增强等)首先创建一个包含该映射的数组(f[]如下),然后您只需按其标签访问值即可:

$ cat file
geo:FR, host:www.example.com
host:www.example.com, geo:FR
foo:bar, host:www.example.com, stuff:nonsense, badgeo:uhoh, geo:FR, nastygeo:wahwahwah

$ cat tst.awk
BEGIN { FS=":|, *"; OFS="," }
{
    for (i=1; i<=NF; i+=2) {
        f[$i] = $(i+1)
    }
    print f["geo"], f["host"]
}

$ awk -f tst.awk file
FR,www.example.com
FR,www.example.com
FR,www.example.com

以上内容可在每个UNIX盒的任何shell中使用任何awk进行工作。

答案 2 :(得分:0)

在这里,我已使用GNU Awk将分隔的key:value对转换为有效的shell分配。使用Bash,您可以使用<(process substitution)将这些分配加载到当前的shell中:

# source the file descriptor generated by proc sub
. < <(

  # use comma-space as field separator, literal apostrophe as variable q
  awk -F', ' -vq=\' '

    # change every foo:bar in line to foo='bar' on its own line
    {for(f=1;f<=NF;f++) print gensub(/:(.*)/, "=" q "\\1" q, 1, $f)}

  # use here-string to load text; remove everything but first quote to use standard input
  ' <<< 'host:www.example.com, geo:FR'
)