通过正则表达式从字符串中提取特定值

通过正则表达式从字符串中提取特定值

我看过很多例子,但我似乎无法做到这一点。 grep 可以只输出匹配的指定分组吗? 例如看起来它应该可以工作,但我得到的是错误或根本没有输出。

我想要做:

pathname="/a/long/path/of/mine/2x02 - bar.mp4"

所有示例都将是长路径、一位或两位数字、x,然后是 2 位数字,后跟空格、a - 和文件名。

我想解析它的 02 值: https://regex101.com/ 表明在本例中 \d{1,2}x(\d\d) 应该匹配 1 = 02。

我不知道的是如果我有

echo "$pathname" | sed -n 's/.*\d{1,2}x\(\d\d\)/\1/p'

或者

echo $pathname | grep -oP '\d{1,2}x(\d\d)'

我什么也没得到。我可以:

echo $pathname | grep -oP '(\d\d)'

但在某些情况下,一行中可能还有其他 2 位数字值,就像我有

/a/long/path/of/mine/12x02 - bar.mp4

在这种情况下,我认为上面不会指定第二个匹配项,所以我更喜欢更具体的正则表达式...如果我可以使用匹配组或其他东西。我正在尝试在 Scientific Linux 7.1 上的 bash 中执行此操作。

答案1

正如您使用grepPCRE ( -P) 一样,您可以使用以下正则表达式模式:

grep -Po '\d{1,2}x\K\d{2}(?= )' <<<"$pathname"
  • \d{1,2}x将匹配后跟的一位或两位数字x,然后\K将放弃匹配

  • \d{2}将精确匹配两个数字,零宽度正向先行模式(?= )确保我们在两个数字后面有一个空格。

所以这应该满足您的要求。

例子 :

$ grep -Po '\d{1,2}x\K\d{2}(?= )' <<<'/a/long/path/of/mine/2x02 - bar.mp4'
02

$ grep -Po '\d{1,2}x\K\d{2}(?= )' <<<'/a/long/path/of/mine/34x12 - bar.mp4'
12

$ grep -Po '\d{1,2}x\K\d{2}(?= )' <<<'/a/long/path/of/mine/0x1 - bar.mp4'
## No match

$ grep -Po '\d{1,2}x\K\d{2}(?= )' <<<'/a/long/path/of/mine/00x1 - bar.mp4'
## No match

答案2

使用 sed

在基本模式下使用 sed,需要转义大括号:

$ echo "$pathname" | sed -n 's/.*[[:digit:]]\{1,2\}x\([[:digit:]][[:digit:]]\).*/\1/p'
02

为了更好的可移植性,我使用[[:digit:]]代替\d.我还添加.*到末尾以删除尾随文本。

使用grep -P

grep -P支持后视功能,但后视文本必须具有固定长度。因此,我们可以查找x要显示的前两位数字之前的单个数字:

$ echo "$pathname" | grep -oP '(?<=\dx)(\d\d)'
02

替代路径

上述两种方法也适用于备用路径:

$ echo '/a/long/path/of/mine/12x02 - bar.mp4' | grep -oP '(?<=\dx)(\d\d)'
02
$ echo '/a/long/path/of/mine/12x02 - bar.mp4' | sed -n 's/.*[[:digit:]]\{1,2\}x\([[:digit:]][[:digit:]]\).*/\1/p'
02

答案3

仅使用 posix shell

p=$pathname
p=${p##*/}
p=${p#*x}
p=${p%% *}
echo "$p"

#or on one line
p=${pathname##*/};p=${p#*x};p=${p%% *};echo "$p"

相关内容