我正在使用 GNU bash 4.3.48
我期望
echo "23S62M1I19M2D" | sed 's/.*\([0-9]*M\).*/\1/g'
會輸出62M19M ......但它沒有。
sed 's/\([0-9]*M\)//g'洗掉 ALL[0-9]*M并檢索23S1I2D。但該小組\1并沒有像我想象的那樣作業。
sed 's/.*\([0-9]*M\).*/ \1 /g', 檢索M ...
我究竟做錯了什么?
謝謝!
uj5u.com熱心網友回復:
問題是它.*是貪婪的。由于 onlyM是強制性的,當引擎找到 last 時M,它滿足正則運算式,因此所有字串都匹配,M被捕獲并因此在用\1反向參考替換后保留。
這意味著,您不能輕松地使用sed. 你可以用 Perl 更容易地做到這一點,因為它支持匹配和跳過模式:
#!/bin/bash
perl -pe 's/\d M(*SKIP)(*F)|.//g' <<< "23S62M1I19M2D"
請參閱在線演示。模式匹配
\d M(*SKIP)(*F)- 一個或多個數字,M, 然后省略匹配并從失敗位置搜索下一個匹配|.- 或匹配除換行符以外的任何字符。
或者簡單地匹配所有出現并連接它們:
perl -lane 'BEGIN{$a="";} while (/\d M/g) {$a .= $&} END{print $a;}' <<< "23S62M1I19M2D"
所有\d M匹配項都附加到在$a處理字串結束時列印的變數。
uj5u.com熱心網友回復:
您的替換可能有效,但沒有替換您認為的內容。
在替換中s/\(foo...\)/\1/,\1匹配任何\(...\)匹配和捕獲的內容,因此您的替換將替換foo...為foo...!
% echo "1234ABC" | sed 's/\([A-Z]\)/-\1-/'g
1234-A--B--C-
所以你需要匹配更多,但只捕獲匹配的一部分。例如:
echo "23S62M1I19M2D" | sed 's/[0-9]*[A-LN-Z]*\([0-9]*M\)/\1/g'
62M19M2D
在sed 's/.*\([0-9]*M\).*/\1/g'(是否出現在問題的編輯中,或者我只是錯過了它?)的情況下,.*匹配“貪婪地” - 它盡可能多地匹配,因此包括M. 在上面的例子中,[A-LN-Z]需要在未捕獲部分的末尾,所以數字被強制匹配[0-9]到捕獲的內部。
在撰寫或解釋正則運算式時,清楚地了解“貪婪”的含義是一個非常重要的想法。
uj5u.com熱心網友回復:
使用您顯示的示例,awk您可以嘗試以下程式。
echo "23S62M1I19M2D" |
awk '
{
val=""
while(match($0,/[0-9] M/)){
val=val substr($0,RSTART,RLENGTH)
$0=substr($0,RSTART RLENGTH)
}
print val
}
'
解釋:簡單的解釋是,使用echo列印值并將其??作為標準輸入發送給awk程式。在awk程式中使用其match函式匹配 it(/[0-9] M) 運行回圈中提到的正則運算式以查找每行中的所有匹配項并在每行的最后列印收集到的匹配值。
uj5u.com熱心網友回復:
如果你知道你將只遇到后綴S,M,I和D,另一種方法是明確洗掉你不想要的組合:
echo "23S62M1I19M2D" | sed 's/[0-9]\ [SID]//g'
這給出了預期的:
62M19M
更新:此變體產生相同的輸出,但拒絕所有非數字、非M后綴:
echo "23S62M1I19M2D" | sed 's/[0-9]\ [^0-9M]//g'
uj5u.com熱心網友回復:
這可能對你有用(GNU sed):
sed -nE '/[0-9]*M/{s//\n&\n/g;s/(^|\n)[^\n]*\n?//gp}' file
用換行符包圍匹配,然后洗掉不匹配的部分。
替代方案,使用 grep 和 tr:
grep -o '[0-9]*M' file | tr -d '\n'
NBtr洗掉所有換行符(包括最后一個)來恢復最后一個換行符,使用:
grep -o '[0-9]*M' file | tr -d '\n' | paste
替代解決方案將所有結果連接成一行。要使用第一個解決方案實作相同的結果,請使用:
sed -nE '/[0-9]*M/{s//\n&\n/g;s/(^|\n)[^\n]*\n?//g;H};${x;s/\n//gp}' file
轉載請註明出處,本文鏈接:https://www.uj5u.com/qukuanlian/348966.html
下一篇:如何獲得exec()的輸出?
