用于从具有可选字符的字符串捕获路径的正则表达式(perl | awk | sed | ..)

时间:2016-05-01 18:22:25

标签: regex perl path

我希望在第一个斜杠之前匹配第一个和最后一个斜杠/之间的所有内容,包括可选的~

我在第一部分使用了这个:

echo ~~a~/dir1/di r2/b.c \
| perl -pe 's/[^\/]*(\/.*\/).*/\1/'

产生/dir1/di r2/

此匹配包括代字号:

perl -pe 's/ * ( \/.*\/).*/\1/'

但为可选字符添加?似乎在这些情况下无效:

perl -pe 's/ 。* ( 〜? \/.*\/).*/\1/' - > /di r2/
perl -pe 's/ 。* ( (?:〜) \/.*\/).*/\1/' - > ~~a/dir1/di r2/b.c

我做错了什么?

2 个答案:

答案 0 :(得分:1)

如果我理解了所需的输出权,那么无论是否使用波形符都可以使用

echo "path /d1/d2/43a/" | perl -nE '$_ =~ m{ ( ~? (?: /.*/ | /) ) }x; say "$1"'

打印

/d1/d2/43a/

相同的Perl代码,在输入

中的第一个斜杠之前带有波浪号
echo "path ~/d1/d2/43a/" | perl -nE '$_ =~ m{ ( ~? (?: /.*/ | /) ) }x; say "$1"'

打印

~/d1/d2/43a/

备注不推荐在替换中使用/1。请改用$1。将{}用于分隔符只允许不必转义/,从而使其更具可读性 - 但是当使用/作为分隔符然后在其中转义时,同样有效。

更新

要抓住单独的~/(或/),最简单的更改是明确添加/.*/ | /。为了在两种情况下捕获(optinal)~,在此周围存在(非捕获)分组。删除-w标志,这样当输入字符串根本没有斜线时,不会发出警告,但只打印一个空行。

答案 1 :(得分:1)

原始要求

档案data

~~a~/dir1/di r2/b.c
/dir1/di r2/z.y
~/dir1/di r3/p.q
gobbledegook~/name/more/still/more/notwanted.c
xxx~//yyy

脚本

perl -ple 's%(?:^.*?)((?:^|~)/.*/).*%$1%' data

示例输出

~/dir1/di r2/
/dir1/di r2/
~/dir1/di r3/
~/name/more/still/more/
~//

这就是你需要的吗?

解析正则表达式

s%(?:^.*?)((?:^|~)/.*/).*%$1%

第一部分(?:^.*?)是一行非捕获非贪婪匹配,用于行开头的任意字符序列。

第二部分((?:^|~)/.*/)是一个捕获表达式,其中包含一个非捕获术语,该术语在行的开头或波浪号处匹配,后跟斜杠和贪婪的任何内容,直到最后一个斜杠在线。

尾随.*匹配第二部分之后的所有内容。

替换就是被捕获的东西;其余的是Perl是Perl。

修订要求

原来的问题陈述似乎不完整。显然:

  

对于单斜杠,它应该仅输出/(如果存在则伴随波形符)。对于没有斜线,最好是空字符串,因为没有匹配。 ...对于这种情况~a b/c/d.f,它返回完整的字符串;相反,它应该返回/c/

所以,这是一个修改过的脚本来处理特殊的额外案例(发生了什么事情以及学习如何捕鱼&#39 ;?)。 ~a b/c/d.f案例在字符串或代字号的开头是?限定词。分组。

修订data档案

~~a~/dir1/di r2/b.c
/dir1/di r2/z.y
~/dir1/di r3/p.q
gobbledegook~/name/more/still/more/notwanted.c
xxx~//yyy
not-a-slash-in-sight
just-the-one/with-extra-info
just-the~/with-more-info
~/one-slash-at-start-with-tilde
/one-slash-at-start-without-tilde
~a b/c/d.f

修订脚本

perl -ple 's%^[^/]*$%%; s%(?:^[^/]*?)((?:^|~)?/)[^/]*$%$1%; s%(?:^[^/]*?)((?:^|~)?/.*/).*%$1%' data

最后对原始表达进行了温和修改。

第一个s///查找没有任何/的行,并将其替换为空。

第二个s///查找带有斜杠的行,可能在波浪号或行首之前,后跟非斜杠到行尾的可选波形符和斜杠。

匹配时前两个的输出与第三个s///不匹配。

修改输出

~/dir1/di r2/
/dir1/di r2/
~/dir1/di r3/
~/name/more/still/more/
~//

/
~/
~/
/
/c/