5. 刪除程序中的各種注釋
- 首先考慮到在字符串中可能存在注釋的文本腾窝,但是這些注釋我們是不需要刪除的卷员,
- 所以可以加一個分支再匹配字符串
- 這時當匹配字符串開始時候盈匾,就會一直匹配到字符串結(jié)束
- 然后下次匹配的時候,是在字符串尾部繼續(xù)應(yīng)用正則表達式毕骡,所以不會匹配到內(nèi)部
- 同理注釋中字符串也不算程序中的字符串威酒,因為在更前的位置,已經(jīng)被當成注釋給匹配了
- 如果既不是字符串也不是注釋挺峡,傳動裝置才會驅(qū)動到下一個位置繼續(xù)嘗試
匹配注釋的表達式
- 多行注釋:
/\*[\s\S]*?\*/
- 單行注釋:
//.*+
匹配字符串的表達式
- 單引號或雙引號 字符串:
(["'])(?:(?!\1)[^\n\\])*+(?:\\.(?:(?!\1)[^\n\\])*+)*+\1
所以整個表達式可以寫成
(["'])(?:(?!\1)[^\n\\])*+(?:\\.(?:(?!\1)[^\n\\])*+)*+\1|/\*[\s\S]*?\*/|//.*+
表達式的順序是不重要的,但是文本中那種內(nèi)容更多可能改變表達式的順序卻可以提高效率
如果要刪除注釋担钮,則替換的時候替換成字符串匹配到的內(nèi)容即可橱赠,如果注釋匹配為空,則無影響箫津,如果字符串為空狭姨,則注釋將被刪除
regex: ((["'])(?:(?!\2)[^\n\\])*+(?:\\.(?:(?!\2)[^\n\\])*+)*+\2)|/\*[\s\S]*?\*/|//.*+
replacement: $1
不使用忽略優(yōu)先量詞和環(huán)視來匹配注釋的更高效版本
-
regex:
((["'])(?:(?!\2)[^\n\\])*+(?:\\.(?:(?!\2)[^\n\\])*+)*+\2)|/\*[^*]*+(?:\*++[^/*][^*]*+)*+\*++/|//.*+
-
replacement:
$1
因為在java中測試宰啦,匹配多行注釋使用這種辦法效率更高,而匹配單引號和雙引號不使用多選分支效率更高
進一步優(yōu)化
- 在匹配非字符串和注釋的時候饼拍,這些內(nèi)容不能被匹配赡模,表達式只能依次嘗試完所有的分支報告當前位置失配,然后由傳動裝置驅(qū)動到下一個位置师抄,因為java采用的是傳統(tǒng)型
nfa
引擎漓柑,表達式主導(dǎo),所以可以自己控制表達式的匹配叨吮, - 在第一個分支加入匹配其他字符的表達式:
[^'/"]+
, 之所以不使用星號量詞是因為*總是能夠匹配成功辆布,而當匹配到注釋開始時,其不能匹配任何文本茶鉴,也能報告成功锋玲,下一次迭代的時候,傳動裝置就會從下一個位置繼續(xù)開始匹配涵叮,這將會把注釋當成其他內(nèi)容匹配而保留下來惭蹂。
([^/'"]++|(["'])(?:(?!\2)[^\n\\])*+(?:\\.(?:(?!\2)[^\n\\])*+)*+\2)|/\*[^*]*+(?:\*++[^/*][^*]*+)*+\*++/|//.*+
- 然而當匹配完字符串后,接下來很可能又是其他字符割粮,所以可以在其后添加匹配其他字符的表達式:
[^'/"]+
盾碗,因為也可能后面存在的是注釋,如
String test = "test"/*middle comments*/;
所以我們應(yīng)該使用星號量詞: [^'/"]*
得到最后的表達式
([^/'"]++|(["'])(?:(?!\2)[^\n\\])*+(?:\\.(?:(?!\2)[^\n\\])*+)*+\2[^/'"]*+)|/\*[^*]*+(?:\*++[^/*][^*]*+)*+\*++/|//.*+
可能還會考慮到優(yōu)化
- 可以把其他字符當作普通字符穆刻,注釋和字符串當作特殊字符
-
normal:
[^/'"]
-
special:
(?:((["'])(?:(?!\2)[^\n\\])*+(?:\\.(?:(?!\2)[^\n\\])*+)*+\2)|(?:/\*[^*]*+(?:\*++[^/*][^*]*+)*+\*++/|//.*+))
- 注釋非捕獲置尔,其他和字符串捕獲,得到:
-
regex:
([^/'"]*+)(?:(?:((["'])(?:(?!\3)[^\n\\])*+(?:\\.(?:(?!\3)[^\n\\])*+)*+\3)|(?:/\*[^*]*+(?:\*++[^/*][^*]*+)*+\*++/|//.*+))([^/'"]*+))*+
-
replacement:
$1$2$4
但實際上這是不正確的氢伟,$2
和$4
捕獲的文本存在于量詞限定之中榜轿,其捕獲的文本時刻在發(fā)生改變,每次都為最后一次應(yīng)用匹配到的文本朵锣。
4. 匹配程序中的字符串
- 程序中的字符串分兩種谬盐,單引號字符串和雙引號字符串
- 匹配雙引號字符串:
"(?:[^\\"\n]|\\.)*+"
- 匹配單引號字符串:
'(?:[^\\'\n]|\\.)*+'
- 消除循環(huán)
"[^\\"\n]*+(?:\\.[^\\"\n]*+)*+"
'[^\\'\n]*+(?:\\.[^\\'\n]*+)*+'
- 可以用一個正則表達式來匹配單引號字符串和雙引號字符串
(["'])(?:(?!\1)[^\n\\]|\\.)*+\1
經(jīng)測試合并后的表達式相比于多選分支具有更高的效率 - 消除循環(huán)
(["'])(?:(?!\1)[^\n\\])*+(?:\\.(?:(?!\1)[^\n\\])*+)*+\1
3. 單純匹配程序多行注釋
special部分匹配的內(nèi)容是normal不能匹配的疑似結(jié)束tag的內(nèi)容,但是special又不會匹配掉結(jié)束tag诚些,所以這里可以把諾干個****...[^/*]
當作special飞傀,****.../
當作結(jié)束tag,之所以不能把*[^/]
當作special诬烹,*/
當作結(jié)束tag砸烦,是因為如果結(jié)束是**/
,這樣的字符绞吁,會造成special匹配**
幢痘,/
被normal部分匹配掉.
不使用忽略優(yōu)先量詞與環(huán)視
- opening:
/\*
- normal:
[^*]
- special:
\*+[^*/]
- closing:
\*+/
regex1:/\*[^*]*+(?:\*++[^/*][^*]*+)*+\*++/
- opening:
/\*
- normal*:
[^*]*\*+
- special:
[^*/]
- closing:
/
regex2:/\*[^*]*+\*++(?:[^/*][^*]*+\*++)*+/
regex3: /\*(?:(?!\*/)[\s\S])*+\*/
regex4: /\*[\s\S]*?\*/
- 在java中的效率比較
1, 2 > 4 > 3
2. 匹配CVS文件的內(nèi)容
- 匹配
hsdh,"gsg ""gsasg""ga",,gs,"",asghs
- 得到
hsdh
,"gsg ""gsasg""ga"
家破,颜说,
gs
购岗,""
,asghs
regex1: (?:(?<=,)|^)(?:[^\n,]*+|"(?:[^\n"]|"")*+")
regex2: (?:(?<=,)|^)(?:[^\n,]*+|"[^\n"]*+(?:""[^\n"]*+)*+")
1. 為數(shù)值添加逗號
問題:
- 將類似
298444215
替換成298,444,215
解決辦法:
- 前面要存在數(shù)字——使用
(?<=\d)
- 后面要存在數(shù)字且是3的整倍數(shù)——
(?=(?:\d\d\d)+$)
regex: (?<=\d)(?=(?:\d{3})++$)
replacement: ,