程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> .NET網頁編程 >> C# >> C#入門知識 >> 去掉[]中的英文字符

去掉[]中的英文字符

編輯:C#入門知識

最近在信息科技大學上傳智.Net就業班的課程,中午有位信息科技大學的老師問我關於正則表達式的問題. 問題大致這麼描述的:
  有一個字符串,裡面是中文與英文的混排內容,中間包含幾對中括號(方括號),現在有個需求,就是移除中括號中所有的英文字符,保留其他數據.
  我一看就覺得可以完成,但是隨手一寫發現有點問題,可能處於數學出身的原因,總想把問題盡量寫得全面,我中午吃飯的時候就在考慮該怎麼些比較好. 這裡給出我思考這個問題的思路,看看有沒有給大家一點啟發.
 
化歸思想
  數學裡面有個很重要的思想,就是“化歸”思想. 什麼是化歸呢?簡單的說,就是將復雜的問題進行歸納總結,將其變成一些簡單的問題的組合,然後簡單問題解決了,復雜問題也就解決了.
  有朋友就會說了:“看了數學頭痛,還跟我提什麼化歸思想… …”
  其實不然,只是化歸思想這個名字很嚇人——數學思想啊,其實她很基礎,因為我們天天都在用這個思想. 來一個生活中的例子,想知道一個超市的商品質量和價格好與不好,怎麼考究?顯然這個咱們沒有辦法一個個檢驗,但是我們看得到,可以比較. 如果這個超市總是人很多,而且消費者投訴也很少,那我們就可以下結論了,這個超市不錯. 再比如說,面向對象中的一個概念,C#中繼承具有傳遞性,這個怎麼理解?其實很簡單,因為繼承,子類包含了父類的成員,那麼一直下去,孫子類繼承子類,就包含了子類成員,即是孫子類包含了父類成員,因此就有了結論,派生類都具有基類成員,自然傳遞性就很好理解了.
 
問題化歸
  那麼說過了這麼多和解決這個問題有什麼關系呢?顯然我解決這個問題使用了化歸的思想. 關鍵是這個問題有什麼難點呢?
我們先來看一個例子:
有一個字符串
1 string str = "abc[你abc好]abc";
現在要將字符串裡面的“[你abc好]”中的英文字符“abc”去掉,使得字符串變為
1 string str = "abc[你好]abc";
顯然使用正則表達式可以是
1 string str = Regex.Replace(str, @"(\[你)[a-zA-Z]+(好\])", "$1$2");
  當然這裡的解答絕對不是唯一的,因此給出的只是一個我想到的方法. 但是關鍵是這個情況是很特殊的. 首先,方括號“[]”中不見得就是漢字在兩邊,而且不見得就是你好;其次,對於中間不一定就是只有一串英文字母,比如還有可能是”你abc好abc啊”,那麼此時就不太管用了.
那麼這裡的問題便是:
  1、方括號內不確定有多少個漢子塊與多少個英文塊;
  2、方括號內不明確英文與漢字排列方式
  那麼將問題化歸一下,就好辦了(注意,本文不見得給出的是最好方法,但是提供了一個思考問題的方法)
漢字兩邊型
  由於問題是要將方括號內的英文字母去掉,所以無論方法括號內兩端是什麼,都可以使用C#語句:
1 string str = Regex.Replace(str, @"(\[)[a-zA-Z]*(.+?)[a-zA-Z]*(\])", "$1$2$3");
  使得字符串中方括號兩邊變成漢字.
  也就是說所有的字符串都可以劃歸為如下模型
…[中…中]…
 
[中a中a中]型
  將字符串變為“漢字兩邊型”後,問題就是不明確兩端漢字中有多少組引文字符,但是自己分析一下,去掉右邊的漢字,那麼字符串將變成由字符串片段“中a”的一個重復的循環組合,即:”中a”、”中a中a”、”中a中a中a”、… …
  那麼問題就簡單了,只要很好的解決“[中a中a中]型”的字符串,那麼其他情況就可以利用循環解決了.
  第一步,從左往右依次去掉第一組英文(當然需要判斷是否存在),例如,將一個的字符串”[中a中a中a中]”通過正則表達式替換變為”[中a中a中]”. 可以使用C#語句
1 if(Regex.IsMatch(str, @"\[[^\]]+?[a-zA-Z]+[^\]]+\]"))
2 {
3     string str = Regex.Replace(str, @"(\[[^\]]+?)[a-zA-Z]+([^\]]+\])", "$1$2");
4 }

  第二步,就很簡單了,剩下的就是重復了,直到剩下“[中a中]型”. 實際上,當剩下該模式字符串時,依舊調用上面的方法,一樣能實現將中間的英文去掉.
 
分析一下匹配規則
  實際上現在已經把問題解決了,下面我說明一下我為何將正則表達式寫成這樣. 我以最後一次匹配為例.
1 string str = "a[中a中]a";
2 if(Regex.IsMatch(str, @"\[[^\]]+?[a-zA-Z]+[^\]]+\]"))
3 {
4     string str = Regex.Replace(str, @"(\[[^\]]+?)[a-zA-Z]+([^\]]+\])", "$1$2");
5 }

分析:
1、此時if判斷中IsMatch判斷是否匹配
  IsMatch中的正則表達式這麼寫“@”\[[^\]]+?[a-zA-Z]+[^\]]+\]””,表示先匹配中括號“[”開頭,然後中間不允許有中括號結束的字符“]”,並且使用了取消貪婪模式使之後面的“[a-zA-Z]+”盡可能的匹配第一組英文字母. 這裡匹配了str中的“[中a”. 然後剩下的“[^\]]+\]”匹配第一組引文字母結束後的所有字符,以及結束的中括號“]”. 因此返回的肯定是true.
2、開始替換
  有了if的匹配以後,替換就很容易了,Replace方法中的正則表達式中首尾兩個組分別匹配“[中”和“中]”,因此,“$1$2”就將中間的引文字母替換掉了.
  對於非最後一次匹配的情況,例如替換”[中a中a中]”,組1匹配“[中”,組2匹配“中a中]”,只是將左邊的第一組英文替換掉了.
 
整合結果
  通過前面的分析,想要將中括號裡面的英文去掉,可采用的通用思維為
-> 先去掉中括號內首尾英文字母
-> 在利用循環,從左往右依次去掉一組組英文字符,直到英文字符為止
  結合前面的討論,給出一個方法
1 public static string MyReplace(string str)
2 {
3     str = Regex.Replace(str, @"(\[)[a-zA-Z]*(.+?)[a-zA-Z]*(\])", "$1$2$3");
4     while (Regex.IsMatch(str, @"\[[^\]]+?[a-zA-Z]+[^]]+\]"))
5     {
6         str = Regex.Replace(str, @"(\[[^\]]+?)[a-zA-Z]+([^\]]+\])", "$1$2");
7     }
8     return str;
9 }

  但是值得思考的是,此處不一定是絕對的解決方案,按照我的思維,一定會有更好的方法出現. 這裡我只是給出了一個思考問題的方法,並擬定出了解決方案.

 

摘自  狄拉克之海 

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved