GT C Sharp cơ bản – Bài 17 : Chương 16: Chuỗi

0
(0)

Chương 16: Chuỗi

 

Tác giả: Sưu tầm

 

Khái quát

Tất cả các chuỗi trong C# là các thể hiện của kiểu System.String trong Common Language Runtime. Bởi vì điều này, nên có nhiều thao tác sẵn có cho phép làm việc với các chuỗi. Ví dụ, lớp String định nghĩa một hàm chỉ mục có thể được sử dụng để duyệt qua các ký tự của chuỗi:

using System;

 

class Test {

     public static void Main() {

          string s = “Test String”;

          for (int index = 0; index < s.Length; index++)

               Console.WriteLine(“Char: {0}”, s[index]);

     }

}

 

Các thao tác

Lớp string là một ví dụ của một kiểu không thay đổi, có nghĩa là các ký tự là các ký tự chứa bên trong chuỗi không thể sửa đổi bởi người sử dụng chuỗi. Tất cả các thao tác được thực hiện bởi lớp string trả ra một phiên bản chuỗi đã sửa đổi hơn là sửa đổi ngay trên phiên bản gọi phương thức.

Lớp String hỗ trợ các phương thức so sánh và tìm kiếm sau:

HÀM

MÔ TẢ

Compare()

So sánh hai chuỗi
CompareOrdinal() So sánh hai miền chuỗi bằng cách sử dụng phép so sánh theo thứ tự
CompareTo() So sánh thể hiện hiện thời với một thể hiện khác
EndsWith() Xác định xem có một chuỗi con tồn tại tại cuỗi chuỗi không
StartsWith() Xác định xem có một chuỗi con tồn tại tại đầu chuỗi không
IndexOf() Trả ra vị trí đầu của một chuỗi con
LastIndexOf() Trả ra vị trí cuỗi của một chuỗi con

Lớp String hỗ trợ các phương thức sửa đổi sau:

HÀM

MÔ TẢ

Concat()

Nối hai hay nhiều chuỗi hay các đối tượng khác nhau. Nếu các đối tượng được truyền vào, hàm ToString() được gọi cho chúng

CopyTo()

Sao chép số lượng xác định các ký tự từ một vị trí trong chuỗi đó vào một mảng

Insert()

Trả ra một chuỗi mới với một chuỗi con được chèn vào tại một vị trí xác định

Join()

Nối một mảng các chuỗi lại với nhau với một ký tự chia cắt giữa mỗi thành phần mảng

PadLeft()

Canh trái một chuỗi trong trường

PadRight()

Canh phải một chuỗi trong trường

Remove()

Xoá các ký tự trong một chuỗi

Replace()

Thay thế tất cả các thể hiện của một ký tự bằng một ký tự khác

Split()

Tạo ra một mảng các chuỗi bằng cách tách một chuỗi tại nơi xuất hiện bất kỳ của một hay nhiều ký tự

Substrng()

Trích một chuỗi con từ một chuỗi

ToLower()

Trả ra một phiên bản in thường của chuỗi

ToUpper()

Trả ra một phiên bản in hoa của chuỗi

Trim()

Xoá ký tự trắng trong một chuỗi

TrimEnd()

Xoá một chuỗi các ký tự tính từ cuỗi chuỗi

TrimStart()

Xoá mọt chuối các ký tự tính từ đầu chuỗi

 

Chuyển đổi đối tượng thành chuỗi

Hàm object.ToString() được chồng bởi các kiểu có sẵn để cung cấp cách chuyển đổi dễ dàng từ một giá trị thành một thể hiện chuỗi của giá trị đó. Gọi ToString() sẽ tạo ra một thể hiện mặc nhiên của một giá trị; một thể hiện khác có thể thu được bằng cách gọi String.Format(). Hãy xem phần về định dạng trong Chương 30, “Khái quát” .NET Frameworks, để biết thêm thông tin.

 

Một ví dụ

Hàm Split() có thể được sử dụng để tách một chuỗi thành các chuỗi con bởi các ký tự chia cắt.

using System;

 

class Test {

     public static void Main() {

          string s = “Oh, I hadn’t thought of that”;

          char[] separators = new char[] {‘ ‘, ‘,’};

          foreach (string sub in s.Split(separators)) {

               Console.WriteLine(“Word: {0}”, sub);

          }

     }

}

Ví dụ này cho ra kết quả sau:

Word: Oh

Word:

Word: I

Word: hadn’t

Word: thought

Word: of

Word: that

Mảng ký tự chia cắt định nghĩa các ký tự mà tại đó chuỗi sẽ bị tách. Hàm Split() trả ra một mảng các chuỗi, và câu lệnh foreach duyệt qua mảng và in nó ra.

Trong trường hợp này, kết quả đặc biệt không hữu ích bởi vì chuỗi “, ” bị tách hai lần. Điều này có thể được sửa lại bằng cách sử dụng các lớp biểu thức bình thường.

 

StringBuilder

Mặc dù String.Format() có thể được sử dụng để tạo ra một chuỗi dựa trên các giá trị của các chuỗi khác, nhưng nó không phải là cách hiệu quả nhất để tập hợp các chuỗi. Thời gian chạy cung cấp lớp StringBuilder để làm quá trình này dễ dàng hơn.

Lớp StringBuilder hỗ trợ các thuộc tính và phương thức sau:

THUỘC TÍNH

MÔ TẢ

Capacity

Trả ra hay thiết đặt số lượng ký tự StringBuilder có thể lưu giữ

[]

Chỉ mục StringBuilder được sử dụng để lấy hay thiết đặt một ký tự tại một vị trí xác định

Length

Trả ra hay thiết đặt độ dài

MaxCapacity

Trả ra hay thiết đặt sức chứa lớn nhất của StringBuilder

PHƯƠNG THỨC

MÔ TẢ

Append()

Thêm một thể hiện chuỗi của một đối tượng

AppendFormat()

Thêm một thể hiện chuỗi của mọt đối tượng, có sử dụng một chuỗi định dạng xác định cho đối tượng

EnsureCapacity()

Đảm bảo StringBuilder có đủ chỗ cho số lượng ký tự nhất định

Insert()

Chèn một thể hiện chuỗi của một đối tượng nhất định tại một ví trí xác định

Remove()

Xoá các ký tự xác định

Replace()

Thay thế tất cả các thể hiện của một ký tự bằng một ký tự mới

Ví dụ sau đây trình bày cách lớp StringBuilder có thể được sử dụng để tạo một chuỗi từ các chuỗi độc lập.

using System;

using System.Text;

 

class Test {

     public static void Main() {

          string s = “I will not buy this record, it is scratched”;

          char[] separators = new char[] {‘ ‘, ‘,’};

          StringBuilder sb = new StringBuilder();

          int number = 1;

          foreach (string sub in s.Split(separators)) {

               sb.AppendFormat(“{0}: {1} “, number++, sub);

          }

          Console.WriteLine(“{0}”, sb);

     }

}

Mã này sẽ tạo ra một chuỗi với các từ đếm, và sẽ cho ra kết quả sau:

1: I 2: will 3: not 4: buy 5: this 6: record 7: 8: it 9: is 10: scratched

Bởi vì lời gọi đến split() xác định cả khoảng trống và dấu phẩy như các ký tự chia cắt, nên nó cho rằng có một từ giữa dấu phẩy và khoảng trống, mà kết quả là một phần tử rỗng.

 

Các biểu thức bình thường

Nếu các hàm tìm kiếm có trong lớp String không đủ khả năng, thì không gian tên System.Text chứa đựng một lớp biểu thức bình thường tên là Regex. Các biểu thức bình thường cung cấp một phương thức rất mạnh để thực hiện tìm kiếm và/hoặc thay thế.

 

Trong khi  có một vài ví dụ về cách sử dụng các biểu thức bình thường trong phần này, một mô tả chi tiết là vượt quá phạm vi của quyển sách. Có một vài sách về biểu thức bình thường là đáp ứng điều đó, và chủ đề này cũng được trình bày trong đa số sách về Perl.

 

Lớp biểu thức bình thường sử dụng một kỹ thuật khá thú vị để có hiệu quả cao nhất. Thay vì thể hiện một biểu thức bình thường cho mỗi so khớp, nó viết một chương trình ngắn để cài đặt một so khớp biểu thức bình thường, và mã này sau đó được thực hiện.

 

Ví dụ trước sử dụng Split() có thể được xem lại để sử dụng một biểu thức bình thường, hơn là các ký tự đơn lẻ, để chỉ rõ cách tách chuỗi sẽ xảy ra. Điều này sẽ loại bỏ từ trống trong ví dụ trước.

// file: regex.cs

// compile with: csc /r:system.text.regularexpressions.dll regex.cs

 

using System;

using System.Text.RegularExpressions;

 

class Test {

     public static void Main() {

          string s = “Oh, I hadn’t thought of that”;

          Regex regex = new Regex(@”( |, )”);

          char[] separators = new char[] {‘ ‘, ‘,’};

          foreach (string sub in regex.Split(s)) {

               Console.WriteLine(“Word: {0}”, sub);

          }

     }

}

Ví dụ này cho ra kết quả sau:

Word: Oh

Word: I

Word: hadn’t

Word: thought

Word: of

Word: that

Trong một biểu thức bình thường, chuỗi được tách hoặc trên một khoảng trắng hoặc trên một dấu phẩy theo sau là một khoảng trống.

 

Phân tách phức tạp hơn

Sử dụng các biểu thức bình thường để cải thiện chức năng của Split() không thật sự thể hiện sức mạnh của chúng. Ví dụ sau sử dụng các biểu thức bình thường để phân tích một tập tin IIS. Tập tin log này như sau:

#Software: Microsoft Internet Information Server 4.0

#Version: 1.0

#Date: 1999-12-31 00:01:22

#Fields: time c-ip cs-method cs-uri-stem sc-status

00:01:31 157.56.214.169 GET /Default.htm 304

00:02:55 157.56.214.169 GET /docs/project/overview.htm 200

 

Đoạn mã sau sẽ phân tích nó thành một hình thức hữu dụng hơn.

// file: logparss e.cs

// compile with: csc logparse.cs /r:system.net.dll /r:system.text.regularexpressions.dll

 

using System;

using System.Net;

using System.IO;

using System.Text.RegularExpressions;

using System.Collections;

 

class Test {

     public static void Main(string[] args) {

          if (args.Length == 0){ //we need a file to parse

               Console.WriteLine(“No log file specified.”);

          }

          else

               ParseLogFile(args[0]);

     }

 

     public static void ParseLogFile(string filename) {

          if (!System.IO.File.FileExists(filename)) {

               Console.WriteLine (“The file specified does not exist.”);

          }

          else {

               FileStream f = new FileStream(filename, FileMode.Open);

               StreamReader stream = new StreamReader(f);

               string line;

               line = stream.ReadLine(); // header line

               line = stream.ReadLine(); // version line

               line = stream.ReadLine(); // Date line

               Regex regexDate= new Regex(@”\:\s(?<date>[^\s]+)\s”);

               Match match = regexDate.Match(line);

               string date = “”;

               if (match.Length != 0)

                    date = match.Group(“date”).ToString();

               line = stream.ReadLine(); // Fields line

               Regex regexLine = new Regex( // match digit or :

                                                            @”(?<time>(\d|\:)+)\s” +

                                                            // match digit or .

                                                            @”(?<ip>(\d|\.)+)\s” +

                                                             // match any non-white

                                                            @”(?<method>\S+)\s” +

                                                            // match any non-white

                                                            @”(?<uri>\S+)\s” +

                                                            // match any non-white

                                                            @”(?<status>\d+)”);

               // read through the lines, add an

               // IISLogRow for each line

               while ((line = stream.ReadLine()) != null) {

                    //Console.WriteLine(line);

                    match = regexLine.Match(line);

                    if (match.Length != 0) {

                         Console.WriteLine(“date: {0} {1}”, date, match.Group(“time”));

                         Console.WriteLine(“IP Address: {0}”, match.Group(“ip”));

                         Console.WriteLine(“Method: {0}”, match.Group(“method”));

                         Console.WriteLine(“Status: {0}”, match.Group(“status”));

                         Console.WriteLine(“URI: {0}\n”, match.Group(“uri”));

                    }

               }

               f.Close();

          }

     }

}

Cấu trúc chung của đoạn mã này là quen thuộc. Có hai biểu thức bình thường được sử dụng trong ví dụ này. Chuỗi ngày và biểu thức bình thường được sử dụng để đối sánh như sau:

#Date: 1999-12-31 00:01:22

\:\s(?<date>[^\s]+)\s

Trong mã , các biểu thức bình thường là thường được viết bằng cách sử dụng cú pháp chuỗi đúng nguyên văn, vì cú pháp biểu thức bình thường cũng sử dụng ký tự sổ ngược (\). Các biểu thức bình thường là được đọc đơn giản nhất nếu chúng được chia thành các thành phần tách biệt. Phần

\:

đối sánh với dấu hai chấm (:). Dấu sổ ngược (\) được đòi hỏi bởi vì dấu hai chaấmtự bản thân nó có nhiều nghĩa khác nữa. Phần

\s

đối sánh với một ký tự đơn lẻ của khoảng trắng (tab hoặc khoảng trống). Trong phần tiếp theo

(?<date>[^\s]+)

?<date> định rõ một giá trị sẽ được đối sánh, nên nó có thể trích rút sau này. [^\s] được gọi là một nhóm ký tự, với ký tự ^ có nghĩa là “không có các ký tự sau”. Do đó nhóm này đối sánh bất kỳ ký tự nào trừ khoảng trắng. Cuối cùng, ký tự + có nghĩa là đối sánh một hay nhiều sự xuất hiện được mô tả ở trên (trừ khoảng trắng). Dấu ngoặc được sử dụng để giới hạn với 1999-12-31. Để đối sánh cẩn thận hơn, chỉ định /d (chữ số) có thể được sử dụng, với toàn bộ biểu thức được viết như sau:

\:\s(?<date>\d\d\d\d-\d\d-\d\d)\s

Biểu thức này là một biểu thức bình thường đơn giản. Một biểu thức bình thường phức tạp hơn được sử dụng để đối sánh mỗi dòng của tập tin log. Do tính quy tắc của mỗi dòng, Split() cũng có thể được sử dụng, nhưng điều này sẽ không như minh hoạ. Các mệnh đề của biểu thức bình thường như sau:

<time>(\d|\:)+)\s // match digit or : to extract time

(?<ip>(\d|\.)+)\s // match digit or . to get IP address

(?<method>\S+)\s // any non-whitespace for method

(?<uri>\S+)\s // any non-whitespace for uri

(?<status>\d+) // any digit for status

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

How useful was this post?

Click on a star to rate it!

Average rating 0 / 5. Vote count: 0

No votes so far! Be the first to rate this post.

Related posts

GT C Sharp cơ bản – Bài 30 : Chương 29:  So sánh C# với các ngôn ngữ khác

GT C Sharp cơ bản – Bài 29 : Chương 28: Dòng lệnh

GT C Sharp cơ bản – Bài 28 : Chương 27: Tính tương hoạt