js正規表示式語法大全 一條正規表示式鬧的烏龍

2021-10-13 16:00:08 字數 2376 閱讀 2704

「實戰elisp」系列旨在講述我使用elisp定製emacs的經驗,拋磚引玉,還請廣大emacs同好不吝賜教——如果真的有廣大emacs使用者的話,哈哈哈。
我要編寫乙個elisp函式,其核心邏輯涉及到替換字串中乙個符合某種模式的子串。舉個例子,字串為"[2020-02-15 sat 14:19]《業務邏輯需要關心同步還是非同步嗎?》",需要替換的是其中的[2020-02-15 sat 14:19]

這個由日期和時間組成的字首在每一次我按下c-c c t的時候會自動產生,因為在org-capture-templates中就是這麼設定的

(setq org-capture-templates

'(("t" "todo" entry (file+headline "~/dropbox/gtd/inbox.org" "tasks")

"* todo %u%?n :properties:n :created_at: %un :id: %(uuidgen-4)n :end:")))

更具體一點,它們產生自其中的轉義序列%u(詳情可以參見org-mode的文件template expansion)。

經過一番不是特別仔細的搜尋後,我決定用string-matchreplace-match函式來完成上述替換子串的需求。

然後便鬧了兩個烏龍。

為了匹配形如[2020-02-15 sat 14:19]這樣的字串,我的直覺便驅使我寫出了這樣的正規表示式

"^[d+-d+-d+ w+ d+:d+]"

在node.js或其它支援shorthand character classes的語言中,上面的正規表示式是可用的。

但是elisp偏偏不是這樣的語言!(elisp所支援的正規表示式語法可以參見這篇文件)因此,在elisp中只好用下面這個正規表示式

"^[[0-9]+-[0-9]+-[0-9]+ [a-za-z]+ [0-9]+:[0-9]+]"

雖然elisp不支援shorthand character classes,但它確實支援character classes,但這樣寫出來的正規表示式更長了

"^[[[:digit:]]+-[[:digit:]]+-[[:digit:]]+ [[:alpha:]]+ [[:digit:]]+:[[:digit:]]+]"

我猜你寧可寫前一種對吧。

這貨是用來修改乙個buffer中的內容的……

最後我根據需求的實際情況,綜合使用string-matchsubstring,以及format實現了替換子串的功能

(defun lt-org--starts-with-timestamp-p (text)

"返回t或nil表示輸入字串是否以乙個inactive timestamp開頭。"

;; emacs的正規表示式並不支援如d和w這樣的類,所以要寫成[0-9]和[a-za-z]的形式

(string-match "^[[0-9]+-[0-9]+-[0-9]+ [a-za-z]+ [0-9]+:[0-9]+]" text))

(defun lt-org--delay-timestamp (text new-timestamp)

"用new-timestamp替換text中的inactive timestamp。

如果text沒有以inactive timestamp開頭,則直接新增new-timestamp。"

(format "%s%s" new-timestamp

(if (lt-org--starts-with-timestamp-p text)

(substring text 22)

text)))

過了很久後,我終於發現了在elisp中做字串替換的正確做法……

只要用replace-regexp-in-string函式就足夠了

(replace-regexp-in-string "^[[0-9]+-[0-9]+-[0-9]+ [a-za-z]+ [0-9]+:[0-9]+]" "abc" "[2020-02-15 sat 14:19]《業務邏輯需要關心同步還是非同步嗎?》")

結果為"abc《業務邏輯需要關心同步還是非同步嗎?》",替換很成功。

閱讀原文

正規表示式語法大全

1 正規表示式 文字框輸入內容控制 2 整數或者小數 0 9 0 9 3 只能輸入數字 0 9 4 只能輸入n位的數字 d 5 只能輸入至少n位的數字 d 6 只能輸入m n位的數字 d 7 只能輸入零和非零開頭的數字 0 1 9 0 9 8 只能輸入有兩位小數的正實數 0 9 0 9 9 只能輸入...

正規表示式語法大全

將下一字元標記為特殊字元 文字 反向引用或八進位制轉義符。例如,n 匹配字元 n n 匹配換行符。序列 匹配 匹配 匹配輸入字串開始的位置。如果設定了 regexp 物件的 multiline 屬性,還會與 n 或 r 之後的位置匹配。匹配輸入字串結尾的位置。如果設定了 regexp 物件的 mul...

JS正規表示式大全

正規表示式中的特殊字元 字元 含意 做為轉意,即通常在 後面的字元不按原來意 釋,如 b 匹配字元 b 當b前面加了反斜桿後 b 轉意為匹配乙個單詞的邊界。或 對正規表示式功能字元的還原,如 匹配它前面元字元0次或多次,a 將匹配a,aa,aaa,加了 後,a 將只匹配 a 匹配乙個輸入或一行的開頭...