Joe*_*oel 393 regex pcre sed greedy regex-greedy
我正在尝试使用sed清理URL行以仅提取域名..
所以来自:
http://www.suepearson.co.uk/product/174/71/3816/
Run Code Online (Sandbox Code Playgroud)
我想要:
(有或没有火车斜线,没关系)
我试过了:
sed 's|\(http:\/\/.*?\/\).*|\1|'
Run Code Online (Sandbox Code Playgroud)
和(逃避非贪婪量词)
sed 's|\(http:\/\/.*\?\/\).*|\1|'
Run Code Online (Sandbox Code Playgroud)
但我似乎无法使非贪婪量词工作,所以它总是最终匹配整个字符串.
cha*_*aos 410
基本或扩展的Posix/GNU正则表达式都不能识别非贪心量词; 你需要一个后来的正则表达式.幸运的是,这个上下文的Perl正则表达式非常容易获得:
perl -pe 's|(http://.*?/).*|\1|'
Run Code Online (Sandbox Code Playgroud)
Gum*_*mbo 239
尝试[^/]*
而不是.*?
:
sed 's|\(http://[^/]*/\).*|\1|g'
Run Code Online (Sandbox Code Playgroud)
ste*_*anB 116
使用sed,我通常通过搜索除分隔符之外的任何内容来实现非贪婪搜索,直到分隔符为止:
echo "http://www.suon.co.uk/product/1/7/3/" | sed -n 's;\(http://[^/]*\)/.*;\1;p'
Run Code Online (Sandbox Code Playgroud)
输出:
http://www.suon.co.uk
Run Code Online (Sandbox Code Playgroud)
这是:
-n
s/<pattern>/<replace>/p
;
搜索命令分隔符而不是/
更容易键入s;<pattern>;<replace>;p
\(
...... \)
,以后可以使用\1
,\2
......http://
[]
,[ab/]
就意味着无论是a
或b
或/
^
是[]
手段not
,然后是除了东西之外的任何东西[]
[^/]
意味着除了/
角色以外*
是重复上一组,所以[^/]*
意味着字符除外/
.sed -n 's;\(http://[^/]*\)
意味着搜索和记住http://
后跟任何字符,除了/
并记住你发现了什么/
所以最后添加另一个/
:sed -n 's;\(http://[^/]*\)/'
但是我们想在域之后匹配其余的行,所以添加.*
\1
)中记住的匹配是域,因此将匹配的行替换为保存在组中的内容\1
并打印:sed -n 's;\(http://[^/]*\)/.*;\1;p'
如果你想在域之后包含反斜杠,那么在组中添加一个反斜杠来记住:
echo "http://www.suon.co.uk/product/1/7/3/" | sed -n 's;\(http://[^/]*/\).*;\1;p'
Run Code Online (Sandbox Code Playgroud)
输出:
http://www.suon.co.uk/
Run Code Online (Sandbox Code Playgroud)
and*_*coz 36
sed不支持"非贪婪"运营商.
您必须使用"[]"运算符从匹配中排除"/".
sed 's,\(http://[^/]*\)/.*,\1,'
Run Code Online (Sandbox Code Playgroud)
PS没有必要反斜杠"/".
rev*_*evo 29
sed
和所有其他正则表达口味!
查找表达式的第一次出现:
POSIX ERE(使用-r
选项)
正则表达式:
(EXPRESSION).*|.
Run Code Online (Sandbox Code Playgroud)
桑达:
sed -r "s/(EXPRESSION).*|./\1/g" # Global `g` modifier should be on
Run Code Online (Sandbox Code Playgroud)
示例(查找第一个数字序列)现场演示:
$ sed -r "s/([0-9]+).*|./\1/g" <<< "foo 12 bar 34"
Run Code Online (Sandbox Code Playgroud)
12
Run Code Online (Sandbox Code Playgroud)
它是如何工作的?
这个正则表达式得益于交替|
.在每个位置,引擎将查找交替的第一侧(我们的目标),如果不匹配,则具有点的交替的第二侧.
匹配下一个直接字符.
由于设置了全局标志,因此引擎会尝试继续逐个字符地匹配输入字符串或目标的末尾.一旦交替左侧的第一个且唯一的捕获组匹配(EXPRESSION)
,则线路的其余部分也立即被消耗.*
.我们现在在第一个捕获组中保持我们的价值.
POSIX BRE
正则表达式:
\(\(\(EXPRESSION\).*\)*.\)*
Run Code Online (Sandbox Code Playgroud)
桑达:
sed "s/\(\(\(EXPRESSION\).*\)*.\)*/\3/"
Run Code Online (Sandbox Code Playgroud)
示例(查找第一个数字序列):
$ sed "s/\(\(\([0-9]\{1,\}\).*\)*.\)*/\3/" <<< "foo 12 bar 34"
Run Code Online (Sandbox Code Playgroud)
12
Run Code Online (Sandbox Code Playgroud)
这个版本与ERE版本类似,但没有涉及更改.就这样.在每个单一位置引擎尝试匹配一个数字.
如果发现,其它下列数字被消耗和捕获并自行的其余部分相匹配立即否则*
手段
更多或零那么它跳过第二捕获组\(\([0-9]\{1,\}\).*\)*
,并在点到达.
匹配单个字符和这个过程继续.
查找第一次出现的分隔表达式:
此方法将匹配第一次出现的分隔字符串.我们可以称之为字符串块.
sed "s/\(END-DELIMITER-EXPRESSION\).*/\1/; \
s/\(\(START-DELIMITER-EXPRESSION.*\)*.\)*/\1/g"
Run Code Online (Sandbox Code Playgroud)
输入字符串:
foobar start block #1 end barfoo start block #2 end
Run Code Online (Sandbox Code Playgroud)
-EDE: end
-SDE: start
$ sed "s/\(end\).*/\1/; s/\(\(start.*\)*.\)*/\1/g"
Run Code Online (Sandbox Code Playgroud)
输出:
start block #1 end
Run Code Online (Sandbox Code Playgroud)
第一个正则表达式\(end\).*
匹配并捕获第一个结束分隔符,end
并且所有子代码都与最近捕获的字符匹配,这些字符是结束分隔符.在这个阶段,我们的输出是:foobar start block #1 end
.
然后将结果传递给第二个正则表达式\(\(start.*\)*.\)*
,该正则表达式与上面的POSIX BRE版本相同.如果start delimiter start
未匹配,则匹配单个字符,否则匹配并捕获起始分隔符并匹配其余字符.
使用方法#2(分隔表达式),您应该选择两个适当的表达式:
EDE: [^:/]\/
SDE: http:
用法:
$ sed "s/\([^:/]\/\).*/\1/g; s/\(\(http:.*\)*.\)*/\1/" <<< "http://www.suepearson.co.uk/product/174/71/3816/"
Run Code Online (Sandbox Code Playgroud)
输出:
http://www.suepearson.co.uk/
Run Code Online (Sandbox Code Playgroud)
ish*_*hak 21
这个帖子真的很旧但我认为人们仍然需要它.让我们说你要杀掉所有东西,直到第一次出现HELLO
.你不能说[^HELLO]
......
所以一个不错的解决方案涉及两个步骤,假设您可以在输入中留下您不期望的唯一单词,比如说top_sekrit
.
在这种情况下,我们可以:
s/HELLO/top_sekrit/ #will only replace the very first occurrence
s/.*top_sekrit// #kill everything till end of the first HELLO
Run Code Online (Sandbox Code Playgroud)
当然,通过更简单的输入,您可以使用更小的单词,甚至可以使用单个字符.
HTH!
小智 16
这可以使用cut来完成:
echo "http://www.suepearson.co.uk/product/174/71/3816/" | cut -d'/' -f1-3
Run Code Online (Sandbox Code Playgroud)
gre*_*lio 16
sed - Christoph Sieghart的非贪婪匹配
在sed中获得非贪婪匹配的技巧是匹配除终止匹配的字符之外的所有字符.我知道,这是一个不费吹灰之力,但我浪费了宝贵的时间,而且shell脚本应该是快速而简单的.所以如果其他人可能需要它:
贪心匹配
% echo "<b>foo</b>bar" | sed 's/<.*>//g'
bar
Run Code Online (Sandbox Code Playgroud)
非贪心匹配
% echo "<b>foo</b>bar" | sed 's/<[^>]*>//g'
foobar
Run Code Online (Sandbox Code Playgroud)
另一种方法,不使用正则表达式,是使用字段/分隔符方法,例如
string="http://www.suepearson.co.uk/product/174/71/3816/"
echo $string | awk -F"/" '{print $1,$2,$3}' OFS="/"
Run Code Online (Sandbox Code Playgroud)
sed
当然有它的位置,但这不是其中之一!
正如迪伊指出:只是使用cut
.在这种情况下,它更简单,更安全.这是一个使用Bash语法从URL中提取各种组件的示例:
url="http://www.suepearson.co.uk/product/174/71/3816/"
protocol=$(echo "$url" | cut -d':' -f1)
host=$(echo "$url" | cut -d'/' -f3)
urlhost=$(echo "$url" | cut -d'/' -f1-3)
urlpath=$(echo "$url" | cut -d'/' -f4-)
Run Code Online (Sandbox Code Playgroud)
给你:
protocol = "http"
host = "www.suepearson.co.uk"
urlhost = "http://www.suepearson.co.uk"
urlpath = "product/174/71/3816/"
Run Code Online (Sandbox Code Playgroud)
正如您所看到的,这是一种更灵活的方法.
(全部归功于迪)