C#快速入門教程(20)—— 字串與正規表示式

曹化宇發表於2018-10-28

前面,我們已經瞭解了string型別的字串,它是System.String型別的別名,定義為不可變字串型別,也就是說,當一個字串的內容確定以後就不能再修改了,如果對字串內容進行操作就會重新分配記憶體來儲存新的字串物件,這樣以來,對於字串的處理效率就不會太高。本課,我們將討論幾個關於字串處理的主題,主要包括String類、StringBuilder類、字串格式化、正規表示式,以及如何使用擴充套件方法來封裝程式碼等。

String類

我們知道,C#中的string型別實際上就是System.String類的別名,這樣就可以使用String類的成員來操作字串了,下面,我們瞭解String類中屬性和方法的基本應用。

首先,我們使用Length屬性可以獲取字串中的字元數量,使用Split()方法可以分割字串,下面的程式碼演示了這兩個成員的使用。

static void Main(string[] args)
{
        string s = "abc,def,ghi";
        Console.WriteLine("字元數:{0}",s.Length);
        string[] arr = s.Split(',');
        for (int i = 0; i < arr.Length; i++)
        {
            Console.WriteLine(arr[i]);
        }
}

程式碼執行結果如下圖所示。

enter image description here

請注意Split()方法的引數,這裡使用了一個逗號(char型別)作為分割字元,而在實際應用中還可以使用更多的分割方法,可以參考MSDN文件靈活應用;String類中的基本成員的應用同樣可以參考MSDN文件。

StringBuilder類

StringBuilder類定義在System.Text名稱空間,用於對文字內容進行高效的操作,如組合、修改、替換等操作。

對文字內容進行組合操作時,StringBuilder物件就比String物件高效;如下面的程式碼,我們將多個字串內容進行組合,基中使用了Append()和AppendFormat()方法,它們可以將多種型別的資料新增到物件中,並組合為文字內容。

using System;
using System.Text;

namespace ConsoleTest
{
    class Program
    {
        static void Main(string[] args)
        {
            StringBuilder sb = new StringBuilder();
            sb.Append("abc");
            sb.AppendFormat(",{0},{1}","def","ghi");
            Console.WriteLine(sb.ToString());
        }
    }
}

本例中,我們使用了StringBuilder類的無引數建構函式,實際上,還有一些比較常用的建構函式版本可以使用,如:

  • StringBuilder(int),引數用於指定StringBuilder物件初始尺寸(可儲存的字元數),有利於合理分配記憶體空間。
  • StringBuilder(string,int),引數一用於指定初始值,引數二用於指定物件的初始尺寸。

由於StringBuider物件在建立時已經分配了初始尺寸,所以,在對其內容操作的效率就會比String物件高;在連線多個字串,或者是將其他型別資料組合成字串時,使用Append()和AppendFormat()方法是非常方便的,如下面的程式碼,我們將int型別的資料新增到StringBuilder物件中。

StringBuilder sb = new StringBuilder("abc",32);
sb.AppendFormat("中有{0}個字元",sb.Length);
Console.WriteLine(sb.ToString());

下面,再來了解StringBuilder類中幾個常用的方法。

static void Main(string[] args)
{
        StringBuilder sb = new StringBuilder("def",128);
        sb.Insert(0, "abc,");
        Console.WriteLine(sb.ToString());
        sb.Replace("def", "xyz");
        Console.WriteLine(sb.ToString());
}

本例,我們使用了StringBuilder物件的兩個方法,分別是:

  • Insert()方法,用於在物件指定的位置插入新內容,引數一指定插入的位置,使用從0到始的索引值;引數二指定插入的內容,可以是各種型別的資料。
  • Replace()方法,將原文字內容中,引數一指定的內容變為引數二指定的內容。

這兩個方法都有一些過載版本,大家可以引數MSDN文件使用。實際開發中,還可以參考StringBuilder物件的更多成員進行操作,從而更高效地處理文字的操作。

字串格式化

前面,我們使用過的Console.WriteLine()方法、StringBuilder物件中的AppendFormat()方法,都可以使用引數進行文字的組合操作,實際上,string.Format()方法也可以完成同樣的任務,只是它們的使用場景不一樣,接下來,我們以string.Format()方法為例來討論格式化輸入字串的問題。

String.Format()方法的第一個引數是一個字串,其中可以使用{0}、{1}等標識指定資料的引數的順序,即{0}為方法的第二個引數,{1}為方法的第三個引數,以此類推;這裡,除了使用資料索引,還可以使用一個字母指定資料的格式,如:

  • C字元,顯示為貨幣格式(當前系統設定)。
  • D字元,顯示整數,並指定顯示的位數。
  • E字元,顯示科學計數法格式。
  • F字元,顯示為浮點數格式,並可指定小數的位數。
  • N字元,使用數字分隔。
  • P字元,顯示百分比格式。
  • X字元,顯示為十六進位制格式;使用x時,a至f顯示為小寫形式。

在這些格式化字串中,除了X的大小寫輸出有區別,其他的字元是不區分大小寫,下面的程式碼演示了字串格式輸出的一些操作。

static void Main(string[] args)
{
        Console.WriteLine("{0:C}",1.23);
        Console.WriteLine("{0:D2}",123);
        Console.WriteLine("{0:D5}", 123);
        Console.WriteLine("{0:F2}",1);
        Console.WriteLine("{0:F2}", 1.225);
        Console.WriteLine("{0:N}",123456789.0123);
        Console.WriteLine("{0:P2}",0.1);
        Console.WriteLine("{0:P2}",0.125);
        Console.WriteLine("{0:X}", 15);
        Console.WriteLine("{0:x}", 15);
}

程式碼執行結果如下圖所示。

enter image description here

正規表示式

簡單的說,正規表示式是通過模式(pattern)來匹配(match)文字內容,並可以進一步操作,如判斷文字格式、查詢和替換內容等。正規表示式的相關資源定義在System.Text.RegularExpressions名稱空間,請注意在程式碼中引用。

使用正規表示式時,模式的定義是很關鍵的,也是難度比較大的操作,我們先通過一個示例來了解正規表示式的基本操作方法;下面的程式碼,我們判斷一個字串的內容是否為6位數字(如郵政編碼或縣級行政區劃程式碼)。

using System;
using System.Text.RegularExpressions;

namespace ConsoleTest
{
    class Program
    {
        static void Main(string[] args)
        {
            string p = "[0-9]{6}?";
            Console.WriteLine(Regex.IsMatch("123456",p));
            Console.WriteLine(Regex.IsMatch("12345",p));
            Console.WriteLine(Regex.IsMatch("abcdef", p));
        }
    }
}

程式碼輸出結果如下圖所示。

enter image description here

本例中,首先使用”[0-9]{6}?”定義了一個模式,其中有兩個部分,第一部分指定了匹配的內容,[0-9]表示0到9數字中一個;第二部分指定內容出現的規則,{6}?表示前面的內容剛好出現6次。實際應用中,匹配內容中還可以使用轉義字元(可以參考字串相關課程);如果不指定出現規則,則內容預設匹配一次。

下面給出一些常用的內容匹配方式。

  • [],匹配其中的一個字元,如[yn]匹配y或n、[a-z]匹配字母a到z、[0-9]匹配0到9的數字。
  • [^],不包含^後指定的字元。
  • .字元,匹配換行符(\n)以外的所有字元。
  • \w,匹配大小寫字母、數字和下畫線。
  • \W,匹配大小寫字母、數字和下畫線以外的字元。
  • \s,匹配空白字元,如空格、製表符等。
  • \S,匹配空白字元以外的字元(可見字元)。
  • \d,匹配十進位制數字。
  • \D,匹配十進位制數字以外的字元。

下面是一些常用的應用規則。

  • ^,指定匹配的內容在字串的開始部分。
  • $,指定匹配內容在字串的結尾部分,或換行符(\n)前。
  • *,匹配前一內容0次或多次。
  • +,匹配前一內容1次或多次。
  • ?,匹配前一內容0次或1次。
  • {n},匹配前一內容n次。
  • {n,},匹配前一內容最少n次。
  • {n,m},匹配前一內容在n到m次之間。
  • {n}?,匹配前一內容正好n次。
  • {n,}?,匹配前一內容至少n次,但儘可能少。
  • {n,m}?,匹配前一內容n到m次,但儘可能多。

正規表示式的功能是非常強大的,合理地應用正規表示式也可以讓大量的文字操作事半功倍,但熟練掌握則需要大量的思考、實踐和總結;下面,我們會封裝幾個關於字串操作的方法,其中就包括正規表示式的應用。

使用擴充套件方法封裝程式碼

首先,我們定義一個靜態類CStr,其中定義一個Combine()方法,如下面的程式碼。

using System;
using System.Collections.Generic;
using System.Text;
using System.Text.RegularExpressions;

namespace ConsoleTest
{
    public static class CStr
    {
        // 組合文字內容
        public static string Combine(this string s,params object[] args)
        {
            return string.Format(s, args);
        }
        //
    }
}

這個程式碼看起來並不複雜,只是對string.Format()方法進行了封裝,下面,我們再看如何使用這個方法。

namespace ConsoleTest
{
    class Program
    {
        static void Main(string[] args)
        {
            string s = "{0},{1}".Combine("abc", 123);
            Console.WriteLine(s);
        }
    }
}

只要引用了CStr類所在的名稱空間,我們就可以直接在string物件中使用Combine()方法,為什麼呢?實際上,我們在定義CStr.Combine()方法時需要注意幾個地方,一是CStr類定義為靜態的,這樣,它的成員也都應該定義為靜態的;而Combine()方法的第一個引數使用了this關鍵字和string型別,這就會將Combine()方法定義為string型別的擴充套件方法。

使用擴充套件方法可以更方便的封裝專案中所需要的常用程式碼,使用起來也更加方便,如按順序連線字串和不同型別資料的操作就可以封裝為CStr.Append()方法,如下面的程式碼。

// 連線字串和基本資料型別
public static string Append(this string s, params object[] objs)
{
    StringBuilder sb = new StringBuilder(s, 128);
     for (int i = 0; i < objs.Length; i++)
         sb.Append(objs[i]);
     return sb.ToString();
 }

下面,我們再封裝兩個關於正規表示式的應用。

    // 判斷是否為電子郵件地址
    public static bool IsEmail(this string addr)
    {
        string p = @"^[a-zA-Z0-9](\w+\.)*\w+@(\w+\.)+\w+$";
        return Regex.IsMatch(addr, p);
    }
    // 判斷是否是11位手機號
    public static bool IsMobile(this string num)
    {
        string p = @"1[0-9]{10}?";
        return Regex.IsMatch(num, p);
    }

下面的程式碼演示了CStr類中Append()方法、IsEmail()方法和IsMobile()方法的使用。

static void Main(string[] args)
{
        Console.WriteLine("abc".Append(",def",123,"***"));
        Console.WriteLine("xxx@yyy.zzz".IsEmail());
        Console.WriteLine("123@163.com".IsEmail());
        Console.WriteLine("abc.xyz".IsEmail());
        Console.WriteLine("12345678910".IsMobile());
        Console.WriteLine("123456789".IsMobile());
        Console.WriteLine("21345678910".IsMobile());
        Console.WriteLine("a2345678910".IsMobile());
}

程式碼執行結果如下圖所示。

enter image description here

請注意,手機號碼和電子郵件只能判斷其格式,如果需要在專案中判斷其有效性,只能通過實際聯絡來驗證,比如常用的方法——給使用者郵箱發個驗證郵件。

本課,我們討論了關於字串和正規表示式常用的操作資源,大家可以在學習和實踐中不斷積累自己的程式碼庫,並進行合理的封裝,以便在專案中靈活、快速地實現所需要的功能。

CHY軟體小屋原創作品!

相關文章