又一道sed題的多種解決

羣裏的討論呵,將自個的答案發到blog上來

:(要求用sed)
     有一根長300釐米的棍子,從左往右塗5釐米黑色,空5釐米,然後再塗5釐米黑色,再空出5釐米,……從右往左塗4釐米黑色,空出4釐米,再塗4釐米黑色,再空出4釐米……兩邊依次塗完之後,問空白處有多少釐米
解答:
看到題目時,出題的人已經給了了一個思路了呵,就是先順序(按五間隔)=>轉置=>再順序(按四間隔),要求用sed處理
然後我根據這個思路,寫了一個簡單的可行解:
  perl -e 'print "0"x300,"/n"'|sed 's/0000000000/1111100000/g;'|sed '//n/!G;s//(./)/(.*/n/)/&/2/1/;//D;s/.//'|sed -r 's/....(....)/1111/1/g' |sed '//n/!G;s//(./)/(.*/n/)/&/2/1/;//D;s/.//'
111110001111111011111111111100111111000011111000111111101111111111110011111100001111100011111110111111111111001111110000111110001111111011111111111100111111000011111000111111101111111111110011111100001111100011111110111111111111001111110000111110001111111011111111111100111111000011111000111111101111
並且結合之前的一個sed腳本,有sed計算出了0個數
perl -e 'print "0"x300,"/n"'|sed 's/0000000000/1111100000/g;'|sed '//n/!G;s//(./)/(.*/n/)/&/2/1/;//D;s/.//'|sed -r 's/....(....)/1111/1/g' |sed '//n/!G;s//(./)/(.*/n/)/&/2/1/;//D;s/.//'|sed 's/1//g' |sed -r 'x; s/.*/0/; G; x; :a; /./! bout; s/.//; H; g; s//n.*//g; s/^9*$/0&/; s/.9*$/x&/; H; s/.*x//; y/0123456789/1234567890/; G; s/([^/n]*)/n.*/n([^/n]*)/n.*/n([^/n]*)x.*$//3/1/n/2/; x;s/.*/n([^/n]*)/n[^/n]*//1/; ba; :out; g;s//n/ /;p;'
然後羣裏的sun給出的另一個更簡明的解:
seq 300|sed 's/.*//;n;s/.*//;n;s/.*//;n;s/.*//;n;n;n;n'|tac|sed 's/.*//;n;s/.*//;n;s/.*//;n;s/.*//;n;s/.*//;n;n;n;n;n'|grep -c .
seq 300|sed 's/.*//;n;s/.*//;n;s/.*//;n;s/.*//;n;n;n;n'|sed -n '1!G;$p;h'|sed 's/.*//;n;s/.*//;n;s/.*//;n;s/.*//;n;s
/.*//;n;n;n;n;n'|sed '/^$/d'|sed -n '$='
sun的思想無疑是清晰簡單的呵,並且能用到較多的特性呵。
我發現自個在分析問題的時候,總是要給自己多設定條件了。使問題複雜化了
比如我那答案,事實上在考慮的時候,思維裏就增加了一個條件:腳本應用於多行文件的,並分別得出每行的計算值了。
因此,我那答案在管道傳輸之羊,都是單行對單行的,
簡單的說,在這種方法下各管道的sed,實際上可以直接合併成一個sed命令;
分開只是按思路上的分步進行處理

而sun的思路,不受這個限制的,很好的利用了管道間的行列轉化呵。
經過進一步的思考,發現我之前那個sed上有bug呵,直接sed -r 's/....(....)/1111/1/g' 和 sed 's/0000000000/1111100000/g; 會出現臨界點的錯誤呵。

於是想到的另一個解法:
perl -e 'print "0"x300;print "/n"'|sed -r 's/./a/g; s/(.{1,5})(.{0,5})//U/1/E/2/g;:a;//`/w/s//w{1,4}$//n/U&/m;//s//w{1,4}$//n&/m;ta; y/aA/n/01/x0/'
111110001111111011111111111100111111000011111000111111101111111111110011111100001111100011111110111111111111001111110000111110001111111011111111111100111111000011111000111111101111111111110011111100001111100011111110111111111111001111110000111110001111111011111111111100111111000011111000111111101111

這個是目前能想到不用管道的方法了-_-(用管道就不能體現sed的圖靈完備性了呵,這裏假設輸入已經給出)
當然,要想得到0的數值,加管道就簡單多了,當然,用管道的話,再用sed就沒多少意義了,隨便用grep或wc啥的
可以
perl -e 'print "0"x300;'|sed -r 's/./a/g; s/(.{1,5})(.{0,5})//U/1/E/2/g;:a;//`/w/s//w{1,4}$//n/U&/m;//s//w{1,4}$//n&/m;ta; y/aA/n//n/x0/x0/ ' |sed -n '$='
74
[root@localhost ~]# perl -e 'print "0"x300;'|sed -r 's/./a/g; s/(.{1,5})(.{0,5})//U/1/E/2/g;:a;//`/w/s//w{1,4}$//n/U&/m;//s//w{1,4}$//n&/m;ta; y/aA/n/0/x0/x0/ ' |wc -c
74

其實,sed做爲圖靈完備(爲什麼現在老把sun這句話掛麪嘴裏了哈?),並不需要用多個命令(通道),單sed命令完全可以搞定
[root@localhost ~]# perl -e 'print "0"x300;print "/n"'|sed -nr 's/./a/g; s/(.{1,5})(.{0,5})//U/1/E/2/g;:a;//`/w/s//w{1,4}$//n/U&/m;//s//w{1,4}$//n&/m;ta; y/aA/n/0/x0/x0/; x; s/.*/0/; G; x; :b; /./! bout; s/.//; H; g; s//n.*//g; s/^9*$/0&/; s/.9*$/x&/; H; s/.*x//; y/0123456789/1234567890/; G; s/([^/n]*)/n.*/n([^/n]*)/n.*/n([^/n]*)x.*$//3/1/n/2/; x;s/.*/n([^/n]*)/n[^/n]*//1/; bb; :out; g;s//n/ /; s/ .*//;p'
74

前半部分相同,後半部分是之前寫的一個sed行字符統計腳本,帶原記錄的,如果不想帶原記錄,可以更簡化
寫了這麼多,其實還是那句話,shell腳本編程的思路決定效率,寫這麼複雜的sed腳本,除了具有學習和練習sed的應用,沒有太多的實用價值。還是sun的思路靈活清晰
未了,再給出一個awk的解法和 perl 解決:

變量說明(可更改變量爲任意正數試驗)
n:初始字符個數,例子中爲300
l:從左邊開始間隔切換的個數,這邊爲5
r:從右邊開始間隔切換的個數,這邊爲4
代碼:
(輸出第一行爲結果,第二行爲0字符數和1字符數


[root@localhost sed]# awk 'BEGIN{n=300;l=5;r=4;c=0;for(i=1;i<=n;i++){k=i%(2*l);j=(n-i+1)%(2*r);if((k>=1&& k<=l)||(j>=1 && j<=r)){printf "1"}else{printf "0";c++}};print "/n"c,n-c}'
111110001111111011111111111100111111000011111000111111101111111111110011111100001111100011111110111111111111001111110000111110001111111011111111111100111111000011111000111111101111111111110011111100001111100011111110111111111111001111110000111110001111111011111111111100111111000011111000111111101111
74 226
[root@localhost sed]# awk 'BEGIN{n=100;l=5;r=4;c=0;for(i=1;i<=n;i++){k=i%(2*l);j=(n-i+1)%(2*r);if((k>=1&& k<=l)||(j>=1 && j<=r)){printf "1"}else{printf "0";c++}};print "/n"c,n-c}'
1111100011111110111111111111001111110000111110001111111011111111111100111111000011111000111111101111
24 76
perl解法:(強大的perl環視)
perl -e '$_="a"x300;  s/(.{1,5})(.{1,5})//U/1/E/2/g; s/a(?=.{0,3}(.{8})*$)/A/g; tr/aA$/01/;print $_,"/n"'
111110001111111011111111111100111111000011111000111111101111111111110011111100001111100011111110111111111111001111110000111110001111111011111111111100111111000011111000111111101111111111110011111100001111100011111110111111111111001111110000111110001111111011111111111100111111000011111000111111101111
發佈了34 篇原創文章 · 獲贊 8 · 訪問量 18萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章