網友William提了一個有意思的問題,他想要分析出程式碼中的各Class, Method, Loop等以{ }夾成的區塊,是否可以用RegEx來達成?

舉例來說,程式碼

main()
{
  int count=0;
  printf ("hello world");
  for (i=0; i<10; i++)
  {
      count++;
  }
}
fun1(int a)
{ return a+1; }
fun2()
{
    doSomething();
}

希望能分解成三個字串"main() {.... }"、"fun1(int a) {...}"跟"fun2() {...}"

我的看法是,以RegEx的文字解析的靈活度,要做出基本的雛型並不難,但如果要做到100%涵蓋所有可能出現的樣式,就得耗費相當可觀的功夫。

如果只以將main, fun1, fun2三個Member抓出來為目標,原則上用一個RegEx Pattern "(?ims)\S+?[(].*?[)]\s*{.*?}"就可以打死,如下: (我借用了CodeProject上的.NET RegText Test來示範)

是不是很簡單呀? 不過Demo多半只會Show較犀利的一面,這個寫法在遇到某些特殊組合時破功。例如: 我如果將"for (i=0..."改成"if (true) { } for(i=0;...",for (i=0馬上被誤認成method,我們可以再限制( )中間不准出現=,Pattern改成"(?ims)\S+?[(][^=]*?[)]\s*{.*?}",就可以解決誤認for的問題,但是while(someBoolean)就不會出現等號,於是我們又要再想如何避開。

這就是我平時應用RegEx處理問題的步驟,先設計出基本Pattern->試跑資料->發現例外->只對例外修改Pattern->跑更多資料->又發現例外->再修改Pattern... 有時候,某些例外實在太難處理了,我還會預先變動文字排列或用Replace的技巧先把某些文字取代掉,避免干擾RegEx的比對,等都處理完了再將它們還原。

以上就是我應用RegEx的一些心得,供大家參考。


Comments

# by kennyshu

我發覺要是用"(?ims)\S+?[(].*?[)]\s*{.*?}"的話,在判斷main的時候會有問題,因為他只有包含到一個"}"而已,最後會少了一個"}"。 我用"(?ims)\S+[(].*?[)]\s*{.*?}\s+[}]*"可以解決這個問題且不會影響到之後的method判斷。不過要是main裡面又多了一層巢狀結構(也就是又多了一層{ }),那又會少掉最後一個"}",和一開始的問題一樣…

# by kennyshu

總算試出一個解決的方法: (?ims)\S+[(].*?[)]\s*{.*?}\s+[^a-zA-Z]+ 這樣無論main還是任何的method,不論有多少層都會包起來。不過到時候接收的string要記得trim(),不然會有一些空行及空白。

Post a comment