試圖通過管道將字串匯入 grep/perl 正則運算式以提取重疊的匹配項。目前,結果似乎只提取了沒有任何“回顧”的連續匹配:
嘗試使用 egrep(在 GNU 和 BSD 上):
$ echo "bob mary mike bill kim jim john" | egrep -io "[a-z] [a-z] "
bob mary
mike bill
kim jim
嘗試使用 perl 風格的 grep (-P):
$ echo "bob mary mike bill kim jim john" | grep -oP "()[a-z] [a-z] "
bob mary
mike bill
kim jim
嘗試使用 awk 只顯示第一個匹配項:
$ echo "bob mary mike bill kim jim john" | awk 'match($0, /[a-z] [a-z] /) {print substr($0, RSTART, RLENGTH)}'
bob mary
我想從一個簡單的作業 bash 管道命令中看到的重疊結果是:
bob mary
mary mike
mike bill
bill kim
kim jim
jim john
有任何想法嗎?
uj5u.com熱心網友回復:
Lookahead 是你的朋友
echo "bob mary mike bill kim jim john" |
perl -wnE'say "$1 $2" while /(\w )\s (?=(\w ))/g'
關鍵是前瞻,作為“零寬度斷言”,不消耗任何東西——同時它仍然允許我們捕獲其中的模式。
因此,當正則運算式引擎匹配一個單詞和空格 ( (\w )\s ) 時,將它們吞噬,然后停在那里并“向前看”,只是為了“斷言”所尋求的模式在那里;\w正如他們所說,它不會從最后一個空格和下一個空格之間的位置移動,也不會“消耗”下一個單詞。
很高興我們也可以捕捉到“可見”的模式,即使它沒有被消耗掉!所以我們得到我們的$1和$2,兩個詞。
然后,由于/g修飾符,引擎繼續尋找另一個單詞 空格,然后是另一個單詞。下一個詞是我們的前瞻發現的詞——所以現在一個詞被消耗了,但下一個詞“尋找”(并捕獲)。等等。
請參閱perlretut 中的 Lookahead 和 Lookbehind 斷言
uj5u.com熱心網友回復:
使用下面的 Perl one-liners,它避免了前瞻(它仍然可以是你的朋友):
對于以空格分隔的單詞:
echo "bob mary mike bill kim jim john" | perl -lane 'print "$F[$_] $F[$_ 1]" for 0..($#F-1);'
對于\w Perl 中定義的單詞,由非單詞字符分隔\W :
echo "bob.mary,mike'bill kim jim john" | perl -F'/\W /' -lane 'print "$F[$_] $F[$_ 1]" for 0..($#F-1);'
Perl 單行使用這些命令列標志:
-e: 告訴 Perl 查找內嵌代碼,而不是在檔案中。
-n: 一次回圈輸入一行,$_默認分配給它。
-l:"\n"在執行行內代碼之前去除輸入行分隔符(默認情況下在 *NIX 上),并在列印時附加它。
-a:在空格或選項中指定的正則運算式上拆分$_為陣列。: 拆分為on (一個或多個非單詞字符),而不是空格。@F-F
-F'/\W /'@F\W
$#F: 陣列的最后一個索引,@F輸入行被分割成這個索引。
0..($#F-1):索引(數字)的范圍,從陣列的第一個 ( 0) 到倒數第二個 ( $#F-1) 索引@F。
$F[$_]and $F[$_ 1]:陣列的兩個連續元素,分別@F帶有索引$_和$_ 1。
還請參見
perldoc perlrun::如何執行 Perl 解釋器:命令列開關
perldoc perlre:Perl 正則運算式(regexes)
perldoc perlre:Perl 正則運算式(regexes):量詞;字符類和其他特殊轉義;斷言;捕獲組
perldoc perlrequick:Perl 正則運算式快速入門
uj5u.com熱心網友回復:
你也可以使用 awk
awk '{for(i=1;i<NF;i ) print $i,$(i 1)}' <<< 'bob mary mike bill kim jim john'
請參閱在線演示。此解決方案迭代所有以空格分隔的欄位并列印當前欄位 ( $i) 欄位分隔符(此處為空格) 后續欄位值 ( $(i 1))。
或者,另一種perl使用非常常見的技術來捕獲正向前瞻中的重疊模式的解決方案:
perl -lane 'while (/(?=\b(\p{L} \s \p{L} ))/g) {print $1}' <<< 'bob mary mike bill kim jim john'
請參閱在線演示。詳情:
(?=- 開始積極的前瞻\b- 一個詞邊界(\p{L} \s \p{L} )- 捕獲組 1:一個或多個字母、一個或多個空格、一個或多個字母
)- 前瞻結束。
此處,僅列印第 1 組值 ( {print $1})。
性能考慮
至于這里的 Perl 解決方案,我的結果是最慢的,而 Timur 是最快的,但是,awk結果證明該解決方案比任何 Perl 解決方案都快。結果:
# ./wiktor_awk.sh
real 0m17.069s
user 0m12.264s
sys 0m5.314s
# ./timur_perl.sh
real 0m18.201s
user 0m15.612s
sys 0m6.139s
# ./zdim.sh
real 0m23.559s
user 0m19.883s
sys 0m7.359s
# ./wiktor_perl.sh
real 2m12.528s
user 1m52.857s
sys 0m20.201s
注意我為每個解決方案創建了 *.sh 檔案,例如
#!/bin/bash
N=10000
time(
for i in $(seq 1 $N); do
<SOLUTION_HERE> &>/dev/null;
done)
然后跑了for f in *.sh; do chmod x "$f"; done(從這里借來的)。
轉載請註明出處,本文鏈接:https://www.uj5u.com/yidong/316262.html
上一篇:PerlOOP看不到新方法
