在C#中實現Python的分片技術
前言
之前在學習Python的時候發現Python中的分片技術超好玩的,本人也是正則表達式熱愛狂,平時用C#比較多,所以決定把Python中的分片技術在C#中實現,添加到個人類庫中,以便日后在寫C#代碼的時候能舔一舔Python的味道。
效果展示
Python版: C#版:
切割技術講解
這里先簡要講解一下Python中的分片技術,其他Python前輩也對此技術有豐富多彩的講解文章,這里只是簡要說明一下,好讓讀者們能知道下怎么回事,如果想更深入了解Python的分片技術,這里並不適合你哦。
分片的對象可以是字符串或者序列,本文提供字符串的實現方法,其實序列差不多的,我也會在最后提供字符串和序列的實現代碼,並且附帶單元測試。
好了,廢話不多說,其實看了上面的Python版的結果,我想聰明的您就略知一二了。分片的模板是:變量[起始位置:終點位置:步長],舉個例子:a="abcdfeghij",那么a[0:2:1]這個的結果就是零位置開始(a的左邊),步長為1(也就是連續取),到2位置結束(從a的左邊開始:0->(a的左邊),1->(b的左邊,a的右邊),2->(c的左邊,b的右邊)->結束),好了,結果就是"ab"。
注意事項:1.步長可以忽略不寫(默認為1),如果步長為2,就每取一個跳過1個,以此類推。
2.可以使用負數a[-3:-1:1],結果是"ef",讀者們可以自己推一下,很簡單。
3.分片技術可以針對字符串,也可以針對序列。
實現過程
這里需要用到正則表達式的技術,可能對一些朋友來說比較難懂,但是我會盡量講解的簡單一點。
首先,要使用分片,有三個參數可以控制:起始位置,結束位置,步長。所以在正則表達式應該嵌入這三個參數變量,在匹配的時候動態生成正則表達式。下面來看需要把這三個參數放到哪里:
起始位置:
1.背景
這里使用肯定逆序環視,什么是肯定逆序環視,就是匹配到的位置那一點向后看,向后看的內容必須符合環視的內容,舉個例子:文本:abc ,正則表達式:(?<=a)b,肯定逆序環視符號:(?<=exp),這個正則表達式的意思就是找到b,然后向后看(左邊),如果是a就匹配成功,結果就是b(因為逆序環視是不納入結果中)。
2.實現
我使用[\s\S]來表示一個任意符號,含有位置參數的部分放到左邊,形成這樣一個正則表達式:
(?<=^[\s\S]{StarIndex,})[\s\S] 注意這里的StarIndex是變量,可以是0,1,2,3..!以StarIndex=2(其實位置是2)為例,匹配一個任意字
符,並且向后看(左邊)是開頭->2個或者多個任意字符。
結束位置:
1.背景
這里使用肯定順序環視,什么是肯定順序環視,就是匹配到的位置那一點向前看,向前看的內容必須符合環視的內容,舉個例子:文本abc ,正則表達式:(?=b)a,肯定逆序環視符號:(?=exp),這個正則表達式的意思就是找到a,然后向前看(右邊),如果是b就匹配成功,結果就是a(因為順序環視是不納入結果中)。
2.實現
有了前面表達式基礎,我需要在后面添加一個順序環視,形成這樣一個表達式(合並過后):
(?<=^[\s\S]{StarIndex,})[\s\S](?=[\s\S]{EndCount}),這里要注意了,EndCount並不是結束位置,計算公式:
EndCount=String.Length-EndIndex。字符串長度-結束位置。
步長:
最后終於到步長了,這是關鍵的一步,用於連接上面兩部的,其實基礎前面已經講了,下面給出加入步長邏輯以后,形成的最后正則表達式:(?<=^[\s\S]{StarIndex,})(?<=^[\s\S]{MiddleCount})[\s\S](?=[\s\S]{EndCount}),步長參數為Step變量,這里的MiddleCount在循環中改變,每次循環都MiddleCount=MiddleCount+Step;循環到最后合並獲取到的字符形成結果字符串!!。
實例演示
最后演示一下具體匹配實例,過程,結果。
字符串:a="abcdefghij"; a.Cut(0,3,1);
循環次數:3-0=3次。
循環一:表達式:(?<=^[\s\S]{0,})(?<=^[\s\S]{0})[\s\S](?=[\s\S]{7})
結果圖: =====》'a'
循環二:表達式(?<=^[\s\S]{0,})(?<=^[\s\S]{1})[\s\S](?=[\s\S]{7})
結果圖:=====》'b'
循環三:表達式(?<=^[\s\S]{0,})(?<=^[\s\S]{2})[\s\S](?=[\s\S]{7})
結果圖:=====》'c'
最終合並結果:"abc"。最后貼一張Python中的結果:.
代碼展示
public static class StringExpander { /// <summary> /// Python中的字符串切片技術,[開始索引:結束索引:步長值] /// </summary> /// <param name="Str">目標字符串</param> /// <param name="StarIndex">開始索引</param> /// <param name="EndIndex">結束索引</param> /// <param name="Step">步長值</param> /// <returns></returns> public static String StringCut(this String Str, Int32 StarIndex, Int32 EndIndex, Int32 Step = 1) { if (EndIndex < 0) { EndIndex = Str.Length + EndIndex; } if (StarIndex < 0) { StarIndex = Str.Length + StarIndex; } StringBuilder sb = new StringBuilder(); Int32 LoopTime = EndIndex - StarIndex; if (EndIndex > Str.Length) { EndIndex = Str.Length; } Int32 EndCount = Str.Length - EndIndex; int j = StarIndex; for (int i = 0; i < LoopTime; i = i + Step) { String RegexString = @"(?<=^[\s\S]{" + StarIndex + @",})(?<=^[\s\S]{" + j + @"})[\s\S](?=[\s\S]{" + EndCount + @"})"; try { sb.Append(Regex.Match(Str, RegexString).Value); } catch { } j = j + Step; } return sb.ToString(); } /// <summary> /// Python中的字符串切片技術,只提供位置 /// </summary> /// <param name="Str">目標字符串</param> /// <param name="StarIndex">位置</param> /// <returns></returns> public static String StringCut(this String Str, Int32 StarIndex) { if (StarIndex < 0) { StarIndex = Str.Length + StarIndex; } return Str.Substring(StarIndex, 1); } }
總結
現在提供的是字符串的實現方法,在下面可以下載Demo,里面有序列的實現方法,思想差不多,但是需要添加點東西。謝謝大家觀看!