自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

.NET中刪除空白字符串的10大方法

開發(fā) 后端
我們有無數(shù)方法可用于刪除字符串中的所有空白。大部分都能夠在絕大多數(shù)的用例中很好工作,但在某些對時間敏感的應(yīng)用程序中,是否采用最快的方法可能就會造成天壤之別。

我們有無數(shù)方法可用于刪除字符串中的所有空白,但是哪個更快呢?

介紹

我們有無數(shù)方法可用于刪除字符串中的所有空白。大部分都能夠在絕大多數(shù)的用例中很好工作,但在某些對時間敏感的應(yīng)用程序中,是否采用最快的方法可能就會造成天壤之別。

如果你問空白是什么,那說起來還真是有些亂。許多人認(rèn)為空白就是SPACE 字符(UnicodeU+0020,ASCII 32,HTML ),但它實(shí)際上還包括使得版式水平和垂直出現(xiàn)空格的所有字符。事實(shí)上,這是一整類定義為Unicode字符數(shù)據(jù)庫的字符。

本文所說的空白,不但指的是它的正確定義,同時也包括string.Replace(” “, “”)方法。

這里的基準(zhǔn)方法,將刪除所有頭尾和中間的空白。這就是文章標(biāo)題中“所有空白”的含義。

[[145166]]

背景

這篇文章一開始是出于我的好奇心。事實(shí)上,我并不需要用最快的算法來刪除字符串中的空白。

檢查空白字符

檢查空白字符很簡單。所有你需要的代碼就是:

 

  1. char wp = ' '
  2. char a = 'a'
  3. Assert.True(char.IsWhiteSpace(wp)); 
  4. Assert.False(char.IsWhiteSpace(a)); 
  5.  
  6. 但是,當(dāng)我實(shí)現(xiàn)手動優(yōu)化刪除方法時,我意識到這并不像預(yù)期得那么好。一些源代碼在微軟的參考源代碼庫的char.cs挖掘找到: 
  7.  
  8. public static bool IsWhiteSpace(char c) { 
  9.     if (IsLatin1(c)) { 
  10.         return (IsWhiteSpaceLatin1(c)); 
  11.     } 
  12.     return CharUnicodeInfo.IsWhiteSpace(c); 
  13.  
  14. 然后CharUnicodeInfo.IsWhiteSpace成了: 
  15.  
  16. internal static bool IsWhiteSpace(char c) 
  17.     UnicodeCategory uc = GetUnicodeCategory(c); 
  18.     // In Unicode 3.0, U+2028 is the only character which is under the category "LineSeparator". 
  19.     // And U+2029 is th eonly character which is under the category "ParagraphSeparator". 
  20.     switch (uc) { 
  21.         case (UnicodeCategory.SpaceSeparator): 
  22.         case (UnicodeCategory.LineSeparator): 
  23.         case (UnicodeCategory.ParagraphSeparator): 
  24.             return (true); 
  25.     } 
  26.  
  27.     return (false); 
  28.  
  29. GetUnicodeCategory()方法調(diào)用InternalGetUnicodeCategory()方法,而且實(shí)際上相當(dāng)快,但現(xiàn)在我們依次已經(jīng)有了4個方法調(diào)用!以下這段代碼是由一位評論者提供的,可用于快速實(shí)現(xiàn)定制版本和JIT默認(rèn)內(nèi)聯(lián): 
  30.  
  31. // whitespace detection method: very fast, a lot faster than Char.IsWhiteSpace 
  32. [MethodImpl(MethodImplOptions.AggressiveInlining)] // if it's not inlined then it will be slow!!! 
  33. public static bool isWhiteSpace(char ch) { 
  34.     // this is surprisingly faster than the equivalent if statement 
  35.     switch (ch) { 
  36.         case '\u0009'case '\u000A'case '\u000B'case '\u000C'case '\u000D'
  37.         case '\u0020'case '\u0085'case '\u00A0'case '\u1680'case '\u2000'
  38.         case '\u2001'case '\u2002'case '\u2003'case '\u2004'case '\u2005'
  39.         case '\u2006'case '\u2007'case '\u2008'case '\u2009'case '\u200A'
  40.         case '\u2028'case '\u2029'case '\u202F'case '\u205F'case '\u3000'
  41.             return true
  42.         default
  43.             return false
  44.     } 

刪除字符串的不同方法

我用各種不同的方法來實(shí)現(xiàn)刪除字符串中的所有空白。

分離合并法

這是我一直在用的一個非常簡單的方法。根據(jù)空格字符分離字符串,但不包括空項(xiàng),然后將產(chǎn)生的碎片重新合并到一起。這方法聽上去有點(diǎn)傻乎乎的,而事實(shí)上,乍一看,很像是一個非常浪費(fèi)的解決方式:

 

  1. public static string TrimAllWithSplitAndJoin(string str) { 
  2.     return string.Concat(str.Split(default(string[]), StringSplitOptions.RemoveEmptyEntries)); 
  3.  
  4. LINQ 
  5.  
  6. 這是優(yōu)雅地聲明式地實(shí)現(xiàn)這個過程的方法: 
  7.  
  8. public static string TrimAllWithLinq(string str) { 
  9.     return new string(str.Where(c => !isWhiteSpace(c)).ToArray()); 

正則表達(dá)式

正則表達(dá)式是非常強(qiáng)大的力量,任何程序員都應(yīng)該意識到這一點(diǎn)。

 

  1. static Regex whitespace = new Regex(@"\s+", RegexOptions.Compiled); 
  2.  
  3. public static string TrimAllWithRegex(string str) { 
  4.     return whitespace.Replace(str, ""); 

字符數(shù)組原地轉(zhuǎn)換法

該方法將輸入的字符串轉(zhuǎn)換成字符數(shù)組,然后原地掃描字符串去除空白字符(不創(chuàng)建中間緩沖區(qū)或字符串)。***,經(jīng)過“刪減”的數(shù)組會產(chǎn)生新的字符串。

 

  1. public static string TrimAllWithInplaceCharArray(string str) { 
  2.     var len = str.Length; 
  3.     var src = str.ToCharArray(); 
  4.     int dstIdx = 0
  5.     for (int i = 0; i < len; i++) { 
  6.         var ch = src[i]; 
  7.         if (!isWhiteSpace(ch)) 
  8.             src[dstIdx++] = ch; 
  9.     } 
  10.     return new string(src, 0, dstIdx); 

字符數(shù)組復(fù)制法

這種方法類似于字符數(shù)組原地轉(zhuǎn)換法,但它使用Array.Copy復(fù)制連續(xù)非空白“字符串”的同時跳過空格。***,它將創(chuàng)建一個適當(dāng)尺寸的字符數(shù)組,并用相同的方式返回一個新的字符串。

public static string TrimAllWithCharArrayCopy(string str) {
    var len = str.Length;
    var src = str.ToCharArray();
    int srcIdx = 0, dstIdx = 0, count = 0;
    for (int i = 0; i < len; i++) {
        if (isWhiteSpace(src[i])) {
            count = i - srcIdx;
            Array.Copy(src, srcIdx, src, dstIdx, count);
            srcIdx += count + 1;
            dstIdx += count;
            len--;
        }
    }
    if (dstIdx < len)
        Array.Copy(src, srcIdx, src, dstIdx, len - dstIdx);
    return new string(src, 0, len);
}

循環(huán)交換法

用代碼實(shí)現(xiàn)循環(huán),并使用StringBuilder類,通過依靠StringBuilder的內(nèi)在優(yōu)化來創(chuàng)建新的字符串。為了避免任何其他因素對本實(shí)施產(chǎn)生干擾,不調(diào)用其他的方法,并且通過緩存到本地變量避免訪問類成員。***通過設(shè)置StringBuilder.Length將緩沖區(qū)調(diào)整到合適大小。

// Code suggested by http://www.codeproject.com/Members/TheBasketcaseSoftware
public static string TrimAllWithLexerLoop(string s) {
    int length = s.Length;
    var buffer = new StringBuilder(s);
    var dstIdx = 0;
    for (int index = 0; index < s.Length; index++) {
        char ch = s[index];
        switch (ch) {
            case '\u0020': case '\u00A0': case '\u1680': case '\u2000': case '\u2001':
            case '\u2002': case '\u2003': case '\u2004': case '\u2005': case '\u2006':
            case '\u2007': case '\u2008': case '\u2009': case '\u200A': case '\u202F':
            case '\u205F': case '\u3000': case '\u2028': case '\u2029': case '\u0009':
            case '\u000A': case '\u000B': case '\u000C': case '\u000D': case '\u0085':
                length--;
                continue;
            default:
                break;
        }
        buffer[dstIdx++] = ch;
    }
    buffer.Length = length;
    return buffer.ToString();;
}

循環(huán)字符法

這種方法幾乎和前面的循環(huán)交換法相同,不過它采用if語句來調(diào)用isWhiteSpace(),而不是亂七八糟的switch伎倆 :)。

public static string TrimAllWithLexerLoopCharIsWhitespce(string s) {
    int length = s.Length;
    var buffer = new StringBuilder(s);
    var dstIdx = 0;
    for (int index = 0; index < s.Length; index++) {
        char currentchar = s[index];
        if (isWhiteSpace(currentchar))
            length--;
        else
            buffer[dstIdx++] = currentchar;
    }
    buffer.Length = length;
    return buffer.ToString();;
}

原地改變字符串法(不安全)

這種方法使用不安全的字符指針和指針運(yùn)算來原地改變字符串。我不推薦這個方法,因?yàn)樗蚱屏?NET框架在生產(chǎn)中的基本約定:字符串是不可變的。

public static unsafe string TrimAllWithStringInplace(string str) {
    fixed (char* pfixed = str) {
        char* dst = pfixed;
        for (char* p = pfixed; *p != 0; p++)
            if (!isWhiteSpace(*p))
                *dst++ = *p;

        /*// reset the string size
            * ONLY IT DIDN'T WORK! A GARBAGE COLLECTION ACCESS VIOLATION OCCURRED AFTER USING IT
            * SO I HAD TO RESORT TO RETURN A NEW STRING INSTEAD, WITH ONLY THE PERTINENT BYTES
            * IT WOULD BE A LOT FASTER IF IT DID WORK THOUGH...
        Int32 len = (Int32)(dst - pfixed);
        Int32* pi = (Int32*)pfixed;
        pi[-1] = len;
        pfixed[len] = '\0';*/
        return new string(pfixed, 0, (int)(dst - pfixed));
    }
}

原地改變字符串法V2(不安全)

這種方法幾乎和前面那個相同,不過此處使用類似數(shù)組的指針訪問。我很好奇,不知道這兩種哪種存儲訪問會更快。

public static unsafe string TrimAllWithStringInplaceV2(string str) {
    var len = str.Length;
    fixed (char* pStr = str) {
        int dstIdx = 0;
        for (int i = 0; i < len; i++)
            if (!isWhiteSpace(pStr[i]))
                pStr[dstIdx++] = pStr[i];
        // since the unsafe string length reset didn't work we need to resort to this slower compromise
        return new string(pStr, 0, dstIdx);
    }
}

String.Replace(“”,“”)

這種實(shí)現(xiàn)方法很天真,由于它只替換空格字符,所以它不使用空白的正確定義,因此會遺漏很多其他的空格字符。雖然它應(yīng)該算是本文中最快的方法,但功能不及其他。

但如果你只需要去掉真正的空格字符,那就很難用純.NET寫出勝過string.Replace的代碼。大多數(shù)字符串方法將回退到手動優(yōu)化本地C ++代碼。而String.Replace本身將用comstring.cpp調(diào)用C ++方法:

FCIMPL3(Object*,
    COMString::ReplaceString,
    StringObject* thisRefUNSAFE,
    StringObject* oldValueUNSAFE,
    StringObject* newValueUNSAFE)

下面是基準(zhǔn)測試套件方法:

public static string TrimAllWithStringReplace(string str) {
    // This method is NOT functionaly equivalent to the others as it will only trim "spaces"
    // Whitespace comprises lots of other characters
    return str.Replace(" ", "");
}

許可證

這篇文章,以及任何相關(guān)的源代碼和文件,依據(jù)The Code Project Open License (CPOL)的許可。

 

 

 

譯文鏈接:http://www.codeceo.com/article/donet-remove-whitespace-string.html
英文原文:Fastest method to remove all whitespace from Strings in .NET

 

責(zé)任編輯:王雪燕 來源: 碼農(nóng)網(wǎng)
相關(guān)推薦

2015-10-29 11:55:30

.NET空白字符串方法

2020-09-07 13:08:36

String空白字符方式

2010-11-25 15:59:33

字符串.NET

2025-04-27 10:02:50

JavaScript前端開發(fā)

2020-09-03 10:13:49

JavaScript字符串pad

2009-07-24 13:01:44

ASP.NET頁面跳轉(zhuǎn)

2010-01-13 15:12:04

VB.NET字符串合并

2010-05-07 08:59:50

ASP.NET

2010-06-21 09:48:43

2009-07-06 13:18:35

Servlet方法

2024-04-01 08:41:39

字符串.NET

2009-07-24 10:06:33

數(shù)據(jù)庫字符串ASP.NET

2009-07-28 10:36:37

ASP.NET讀取Ex

2020-10-16 18:35:53

JavaScript字符串正則表達(dá)式

2020-05-14 10:24:41

YAML配置字符串

2009-11-26 18:28:07

PHP函數(shù)trim()

2013-07-15 11:00:18

提升WI-FI信號強(qiáng)度

2021-05-18 09:08:18

字符串子串對象

2024-06-11 07:34:58

C#字符串性能

2021-08-26 05:08:25

相鄰重復(fù)項(xiàng)算法
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號