[LINQ và chuỗi] Phần 1: Đếm số lần xuất hiện của từ trong đoạn văn bản

519 lượt xem

LINQ có thể dùng để truy vấn và chuyển đổi các chuỗi và tập hợp chuỗi, đặc biệt là rất hữu ích với dữ liệu bán cấu trúc trong các tập tin văn bản. Các truy vấn LINQ có thể kết hợp với các hàm về string thông thường và các biểu thức chính quy.

Ví dụ, bạn có thể dùng phương thức Split (tách chuỗi) để tạo 1 mảng các chuỗi và sau đó để truy vấn hay thay đổi bằng LINQ. Bạn cũng có thể dùng phương thức IsMatch trong mệnh đề where của truy vấn LINQ. Và bạn cũng có thể dùng LINQ để truy vấn hay thay đổi các kết quả MatchCollection được trả về bởi 1 biểu thức chính quy.

Trong loạt bài LINQ và Chuỗi (LINQ and Strings) này, chúng ta sẽ đi vào xem xét và nghiên cứu 2 thể loại chính:

  • Truy vấn khối văn bản
  • Truy vấn dữ liệu bán cấu trúc trong 1 định dạng văn bản.

Loạt bài LINQ và chuỗi giúp người học biết cách tương tác với chuỗi bằng LINQ và là bước khởi đầu cho các nhà nghiên cứu về Semantic Web nếu sử dụng LINQ và C# để triển khai dự án. Trong bài này, chúng ta tìm hiểu về dùng LINQ để thao tác với số lượng từ trong 1 đoạn văn bản.

Đếm số lần xuất hiện 1 từ trong đoạn văn bản
Ví dụ sau mô tả cách đếm số lần xuất hiện của 1 từ trong 1 đoạn văn bản (string). Đầu tiên, phương thức Split sẽ tách các từ ra thành 1 mảng. Do đó phương thức Split có thể ảnh hưởng đến hiệu suất thực thi. Nếu bài toán chỉ là đếm số lượng từ, bạn nên cân nhắc dùng phương thức Matches hoặc IndexOf. Tuy nhiên, nếu bài toán không tính đến hiệu suất, bạn có thể dùng phương thức Split để tách từ và sau đó dùng LINQ để đếm số lượng các từ/cụm từ trong 1 đoạn văn bản cho trước.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace LINQ2String
{
    class Program
    {
        static void Main(string[] args)
        {
            // Đoạn văn bản mẫu --- dammio.com
            // Ký hiệu @ dùng định dạng chuỗi ký tự đúng nguyên văn
            // Ví dụ: @"C:\Dammio\LINQ" giống như "C:\\Dammio\\LINQ"  
            string text = @"LINQ extends the language by the addition of query expressions, " +
            @" which are akin to SQL statements, and can be used to conveniently extract and " +
            @" process data from arrays, enumerable classes, XML documents, relational databases, " +
            @" and third-party data sources.";

            // Từ khóa cần tìm kiếm
            string searchTerm = "to";

            //Chuyển đoạn văn thành các từ ngăn cách với các dấu như chấm, phẩy, ...
            //RemoveEmptyEntries là bỏ nhiều khoảng trắng giữa các từ
            string[] source = text.Split(new char[] { '.', '?', '!', ' ', ';', ':', ',' }, StringSplitOptions.RemoveEmptyEntries);

            // Tạo truy vấn LINQ  
            // Dùng phương thức ToLowerInvariant để so khớp hoa thường cụm từ là như nhau
            // Ví dụ: "dammio" và "Dammio"   
            var matchQuery = from word in source
                             where word.ToLowerInvariant() == searchTerm.ToLowerInvariant()
                             select word;

            // Đếm số từ khóa tìm thấy và trả về kết quả 
            int wordCount = matchQuery.Count();
            Console.WriteLine("Tim thay tu khoa \"{0}\" xuat hien {1} trong doan van ban.", searchTerm, wordCount);

            // Giữ cửa sổ trong chế độ debug
            Console.WriteLine("Nhan bat ky phim nao de thoat chuong trinh.");
            Console.ReadKey();  
        }
    }
}
/* Ket qua
	Tim thay tu khoa "to" xuat hien 2 lan trong doan van ban.
	Nhan bat ky phim nao de thoat chuong trinh.
*/

Đếm đoạn văn bản có bao nhiêu từ
Tiếp theo phần trên, một khi đã dùng hàm Split tách thành mảng các từ thì bạn cũng có thể đếm số lượng phần tử mảng này để biết được số lượng từ trong đoạn văn bản (source.Length).

Cách 1

// Đoạn văn bản mẫu --- dammio.com
// Ký hiệu @ dùng định dạng chuỗi ký tự đúng nguyên văn
// Ví dụ: @"C:\Dammio\LINQ" giống như "C:\\Dammio\\LINQ"  
string text = @"LINQ extends the language by the addition of query expressions, " +
@" which are akin to SQL statements, and can be used to conveniently extract and " +
@" process data from arrays, enumerable classes, XML documents, relational databases, " +
@" and third-party data sources.";

//Chuyển đoạn văn thành các từ ngăn cách với các dấu như chấm, phẩy, ...
string[] source = text.Split(new char[] { '.', '?', '!', ' ', ';', ':', ',' }, StringSplitOptions.RemoveEmptyEntries);

Console.WriteLine(text); 
Console.WriteLine("---------------------------------------");
// Đếm số lượng từ trong văn bản
Console.WriteLine("So tu trong doan van ban la: " + source.Length);

// Giữ cửa sổ trong chế độ debug
Console.WriteLine("Nhan bat ky phim nao de thoat chuong trinh.");
Console.ReadKey();    

Có nhiều cách đếm số lượng từ trong 1 đoạn văn mà không dùng phương thức Split, tuy nhiên lại không có cách nào ngắn hơn Split.

Cách 2
Chúng ta có thể dùng phương thức Matches (1 phương thức cực mạnh với chuỗi) để đếm số lượng từ. Tuy nhiên, kết quả có được là 1 mảng các từ chưa có lọc các dấu câu như dấu chấm, dấu phẩy. Ví dụ mảng sẽ cho ra các kết quả như “XML”, “documents,” hay “sources.”, bước tiếp theo là chúng ta cần lọc các dấu câu này.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;

namespace LINQ2String
{
    class Program
    {
        static void Main(string[] args)
        {
            // Đoạn văn bản mẫu --- dammio.com
            // Ký hiệu @ dùng định dạng chuỗi ký tự đúng nguyên văn
            // Ví dụ: @"C:\Dammio\LINQ" giống như "C:\\Dammio\\LINQ"  
            string text = @"LINQ extends the language by the addition of query expressions, " +
            @" which are akin to SQL statements, and can be used to conveniently extract and " +
            @" process data from arrays, enumerable classes, XML documents, relational databases, " +
            @" and third-party data sources.";

            MatchCollection collection = Regex.Matches(text, @"[\S]+");

            Console.WriteLine(text);
            Console.WriteLine("---------------------------------------");

            // Đếm số lượng từ trong văn bản
            Console.WriteLine("So tu trong doan van ban la: " + collection.Count);
           
            // Giữ cửa sổ trong chế độ debug
            Console.WriteLine("Nhan bat ky phim nao de thoat chuong trinh.");
            Console.ReadKey();  
        }
    }
}

Cách 3
Như cách 1 và cách 2, cách 3 cũng không dùng LINQ mà dùng 1 hàm tự tạo để đếm số lượng từ trong 1 đoạn văn như sau, kết quả hàm này cũng giống như cách 1 và cách 2.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;

namespace LINQ2String
{
    class Program
    {
        static void Main(string[] args)
        {
            // Đoạn văn bản mẫu --- dammio.com
            // Ký hiệu @ dùng định dạng chuỗi ký tự đúng nguyên văn
            // Ví dụ: @"C:\Dammio\LINQ" giống như "C:\\Dammio\\LINQ"  
            string text = @"LINQ extends the language by the addition of query expressions, " +
            @" which are akin to SQL statements, and can be used to conveniently extract and " +
            @" process data from arrays, enumerable classes, XML documents, relational databases, " +
            @" and third-party data sources.";

            Console.WriteLine(text);
            Console.WriteLine("---------------------------------------");

            // Đếm số lượng từ trong văn bản
            Console.WriteLine("So tu trong doan van ban la: " + CountWords(text));
           
            // Giữ cửa sổ trong chế độ debug
            Console.WriteLine("Nhan bat ky phim nao de thoat chuong trinh.");
            Console.ReadKey();  
        }
        public static int CountWords(string s)
        {
            int c = 0;
            for (int i = 1; i < s.Length; i++)
            {
                if (char.IsWhiteSpace(s[i - 1]) == true)
                {
                    if (char.IsLetterOrDigit(s[i]) == true || char.IsPunctuation(s[i]))
                    {
                        c++;
                    }
                }
            }
            if (s.Length > 2)
            {
                c++;
            }
            return c;
        }
    }
}

Cách 4
Sau khi trình bày các cách không dùng LINQ, đến đây chúng ta sẽ dùng LINQ để đếm số lượng các từ. Thật tiếc là hiện admin chưa tìm cách nào đếm số lượng từ tốt cả, cách tốt nhất tìm thấy trình bày như ví dụ sau, nhưng số lượng từ đếm được là 40 từ thay vì 38 từ.

 // Đếm số lượng từ trong văn bản
var target = "  ";
var count = text.Select((c, i) => text.Substring(i)).Count(sub => sub.ToUpper().StartsWith(target));
Console.WriteLine("So tu trong doan van ban la: " + count);

Mời bạn thử xem có cách nào dùng LINQ để đếm số lượng từ trong 1 chuỗi/đoạn văn bản không nhé.

Kết luận: Bài viết đã trình bày tổng quan về mối quan hệ giữa LINQ và chuỗi cũng như các cách đếm số từ, số lần xuất hiện của 1 từ trong chuỗi.

Bình luận Facebook

Để lại bình luận

Be the First to Comment!

Notify of
avatar
1000
wpDiscuz