紀念在一個 Regular Expression 小問題卡住的二十分鐘。

手上有份 Oracle DDL (Data Definition Langauge) PL/SQL 指令稿,其中以 / 符號串接多組資料表、View 及 Trigger 建立指令,在 SQL Plus 裡 / 符號可觸發執行動作。(延伸閱讀:Understanding Slashes and Semicolons in Oracle DDL Scripts)

CREATE TABLE X ...
/
CREATE TABLE Y ...
/
CREATE VIEW V ...
/
GRANT ALL ON ...
/

我想寫一段 C# 拆解這些指令,分段交由 Managed ODP.NET 執行。由以上語法,最好的分隔點是「整行只有"/"一個字元」的地方,腦中馬上想到的工具是 Regex.Split,樣式用 "(?m)^/$",事與願違:

鬼打牆一陣子,從官方文件查到,字串起首與結尾標記其實不只 ^ 與 $:

  • ^
    位於整個字串的起始,多行模式時為該行文字的起始。
  • $
    位於整個字串的結尾,多行模式時為位於字串結尾或是該行結尾 \n 字元前頭。
  • \A
    位於整個字串的起始,忽略多行模式。
  • \Z
    位於整個字串的結尾或是字串結尾 \n 字元前方,忽略多行模式。
  • \z
    位於整個字串的結尾。
  • \G
    緊接在前一個比對相符項目的尾端。
  • \b
    位於英文字的邊界。Word Boundary
  • \B
    不可位於英文字的邊界。

由 $ 在多行模式的定義,要嘛是整個字串的結尾,要嘛就是在換行符號 \n 前方,而 Windows 的換行是 \r\n,/ 符號所在行其實是 "\r\n/\r\n",/ 後面還有一個 \r,故不滿足「/$」等於「/ 在換行符號 \n 前方」這項條件,因此要稍加修改為 "(?m)^/r?$",允於 / 與 \n 之間有一個或零個 \r,修改後總算跑出預期結果:

以上做法可通吃 "\n"(UNIX) 或 "\r\n"(Windows) 兩種換行標示法,如果很確定換行符號一定是 "\r\n",也不需保留未來 / 前後允許有空白的彈性,則還有更簡單的做法 - raw.Split(new string[] { "\r\n/\r\n" }, StringSplitOptions.RemoveEmptyEntries):

Tips of using Regex.Split with start of string or line, end of stirng or line.


Comments

# by 凱大

(\n[\t\s]{1,}\r?\n)+ 也是非常好用的東西 XD

Post a comment