一些簡單的例子
這個單元裡, 我們看很多個簡單的例子。 不必擔心, 不需要記憶, 甚至不需要理解 perl 及複雜的命令列語法; 這些部分只求稍微有印象。 目前真正需要理解/記憶的重點, 是 regexp 部分的變化, 請把注意力放在 /.../ 之間以及它對文字檔的效果就好。
* * * * * * *
想抓出 tools.php 這篇 html 文件當中 (幾乎) 所有的超連結,
可以這樣下: perl -ne 'print if /href *=
*"[^"]*"/' tools.php
效果相當於 egrep
href *= *"[^"]*" tools.php
如果要忽略大小寫, 就用 "ignore" 這個選項: perl -ne 'print
if /href *= *"[^"]*"/i'
tools.php
或具有同等效果的 egrep -i 'href *= *"[^"]*"' tools.php
但是這樣會抓到一整列 (含有超連結的所有列)。 如果不要前後文,
只要超連結本身, 就把對應到超連結部分的 regexp 用小括弧括起來,
並且在列印時指名要印這部分。 下面這句不要重抄一遍,
請用上箭頭把上一個例子的指令叫出來修改。 perl -ne 'print
"$1\n" if /href *= *"([^"]*)"/'
tools.php
這裡的 $1 表示
"第一對小括弧裡面的東西"。 順便一提: 這裡的 print ... if
...
文法, 跟英文的句子一樣, 其實是先算 if, 後算 print。
更好的寫法是將空格改寫成 \s 表示
"任何一個空格類字元", 像這樣: /href\s*=\s*"([^"]*)"/
這樣才不會漏掉 tab
字元。
也可以做相反的搜尋。 例如想將檔案當中的空白列都刪除, 可以這樣下:
perl -ne 'print if not /^\s*$/'
tools.php
這裡的 $ 表示:
所搜尋的字串, 必須出現在一列的最後面, 我們才有興趣; 整個 regexp
翻譯成白話文就是: "一列從頭到尾沒有東西, 或是只有空白類字元"
* * * * * * *
(這個例子要在很多人共用的伺服器上實驗, 才有意思。)
想要知道誰精進勇猛, 上機時間超過一小時嗎? 請下 last
指令。 如果資料太多, 用 less 一頁一頁看: last | less
。
最前面的欄位是使用者代號; 最後面小括弧裡面的是每次登入的時間。
假設從來沒有人登入超過 9 小時 59 分, 則可以這樣尋找用功人士:
last | perl -ne 'print "$2 $1\n" if /(\w+).*\((0[^0]:\d\d)\)/'
如果在最後面再加上
| sort
還可以排名次。 這裡的 \d 等同於 [0-9] 也就是
"任何一個數字字元 (digit)" 的意思。 至於 \( 與 \)
則是在比對左小括弧與右小括弧這兩個字元。 前面的倒斜線意思是:
"我就是要比對後面這個字元, 請暫時取消它在 regexp
裡面的特殊意義"。
這個例子用到 regexp 的兩大特性: 猴急 & 貪婪。 後面學到這兩個觀念的時候, 記得回頭來自行解釋。 又, 9:59 的假設, 其實可以拿掉, 但 regexp 需要變得更複雜些, 要用到 |。 一樣, 這也作為以後學到 | 時的作業。
* * * * * * *
這個檔案 的第二欄靠左對齊;
希望將它改成靠右對齊: perl -pe 's/ (\d) *$/ $1/'
unaligned.txt
* * * * * * *
製作網頁時, 「內容與外觀分開處理」 [1, 2] 的觀念很重要。 其中一項原則是: 盡量用描述文意的 <em>...</em> 取代描述外觀的 <i>...</i> 又盡量用描述文意的 <strong>...</strong> 取代描述外觀的 <b>...</b>
如何修改一個網頁檔 fs-value.html
讓它符合這兩個原則? 先這樣下: perl -pe 's/<i>/<em>/' fs-value.html
但是這並沒有真的存檔, 只是將修改結果很快地呈現在畫面上而已。
在後面加上大於符號, 用 輸出重新導向 (output redirection)
將結果另存新檔, 叫做 c056.php 好了: perl -pe 's/<i>/<em>/' fs-value.html >
c056.php
再用 ls -l
檢查,
發現確實多了一個檔案。 開兩個文字視窗 (或 pietty 連線), 分別用 less
去看這兩個檔案有什麼差別。 再開第三個文字視窗, 用 diff
fs-value.html c056.php | less
直接比較差異處。
當然, 這只有改到開頭 "<em>" , 沒有改到結尾 "</em>"。
可以將指令串聯起來, 像這樣:
perl -pe 's/<i>/<em>/' fs-value.html | perl -pe
's/<\/i>/<\/em>/' >
c056.php
整串命令打在同一列, 中間不要換列; 但若分幾次剪貼,
中間應該補上空格。
簡單一點的寫法是: 在同一句 perl 裡面連做兩個代換
s/.../.../
中間並用分號隔開:
perl -pe 's/<i>/<em>/; s/<\/i>/<\/em>/' fs-value.html >
c056.php
其實如果改用 # (或其他任何標點符號) 取代 / 當做分隔符號, 那麼
\/ 前面的倒斜線就可以省略了:
perl -pe 's#<i>#<em>#; s#</i>#</em>#' fs-value.html >
c056.php
事實上不只是代換句型可以自選標點符號取代斜線,
比對字串的句型也可以, 但前面要加一個 "m" (match 的意思)。
例如刪除空白列的例子, 可以寫成: perl -ne 'print if not
m+^\s*$+' tools.php
當然,
要避免選用您的 regexp 裡面有用到的標點符號,
不然反而是自找麻煩了。
用 diff 比較原來的 fs-value.html 及新產生的 c056.php 這兩個檔案,
發現有些地方並未修改完全。
一列上如果出現兩次或兩次以上的搜尋標的物, 則只有第一個會被代換掉。
想將整列上不論出現多少次的所有標的物都取代掉, 就應該在最後面加上
"g" (global 的意思)。 另外, 最好也加上 "i" (ignore 的意思),
不分大小寫都要取代。 最後變成這樣:
perl -pe 's#<i>#<em>#gi; s#</i>#</em>#gi' fs-value.html >
c056.php
是否可能進一步將兩句 s/.../.../ 合併成一句呢? 提示: (1) 要比對 "i 前面有斜線或沒有斜線" 可以用問號 (2) 前面如果有斜線, 代換的字串裡面也要有; 前面如果沒有斜線, 代換的字串裡面也不該有。 這可以用 $1 達成。 答案在網頁原始碼某處。
- 本頁最新版網址: https://frdm.cyut.edu.tw/~ckhung/b/re/simple.php; 您所看到的版本: February 14 2012 10:32:25.
- 作者: 朝陽科技大學 資訊管理系 洪朝貴
- 寶貝你我的地球, 請 減少列印, 多用背面, 丟棄時做垃圾分類。
- 本文件以 Creative Commons Attribution-ShareAlike License 或以 Free Document License 方式公開授權大眾自由複製/修改/散佈。