2012-04-30 46 views
78

Tôi đang cố gắng lấy số lần xuất hiện của một ký tự nhất định như & trong chuỗi sau.Số lần xuất hiện của một ký tự trong một chuỗi

string test = "key1=value1&key2=value2&key3=value3"; 

Làm cách nào để xác định rằng có 2 ký hiệu (&) trong biến chuỗi thử nghiệm ở trên?

+4

Tại sao regex ?????? – CodesInChaos

+2

@CodeInChaos Bởi vì một số người, khi đối mặt với một vấn đề, nghĩ rằng "Tôi biết, tôi sẽ sử dụng các biểu thức chính quy." – Tanzelax

+0

@Tanzelax. [Giống như cái này] (http://stackoverflow.com/questions/1732348/regex-match-open-tags-except-xhtml-self-contained-tags)? **: -) ** – gdoron

Trả lời

189

Bạn có thể làm điều này :

int count = test.Split('&').Length - 1; 

Hoặc với LINQ:

test.Count(x => x == '&'); 
+4

Điều đáng chú ý là cách tiếp cận đầu tiên có thể cực kỳ tốn kém, nếu chuỗi lớn. Trường hợp xấu nhất nếu chuỗi lớn và (gần như) hoàn toàn được tạo thành từ dấu phân cách lặp lại (&), nó có thể phân bổ 12-24x kích thước ban đầu của chuỗi do chi phí đối tượng trong .Net. Tôi sẽ đi với cách tiếp cận thứ hai, và nếu đó là không đủ nhanh sau đó viết một vòng lặp for. –

9

Tại sao lại sử dụng regex cho điều đó. String thực hiện IEnumerable<char>, vì vậy bạn chỉ có thể sử dụng LINQ.

test.Count(c => c == '&') 
22

LINQ có thể làm tất cả mọi thứ ...:

string test = "key1=value1&key2=value2&key3=value3"; 
var count = test.Where(x => x == '&').Count(); 

Hoặc nếu bạn thích, bạn có thể sử dụng quá tải Count mà phải mất một vị ngữ:

var count = test.Count(x => x == '&'); 
+0

LINQ cũng * chậm hơn * khi làm mọi thứ. [Kiểm tra trang web này để biết điểm chuẩn] (http://blogs.davelozinski.com/curiousconsultant/csharp-net-fastest-way-to-check-if-a-string-occurs-within-a-string) nếu bạn muốn * mã * nhanh. –

+0

@ FreeCoder24 không phải là vấn đề của LINQ, mà là trình biên dịch kém. Ví dụ. ví dụ nên được gạch chân thành một vòng lặp đơn giản * (giống như trong C++ và Haskell) *. –

+0

@ FreeCoder24, giống như C# chậm hơn Assembly trong mọi thứ. Nếu bạn muốn mã _fast_, hãy sử dụng Assembly. Và BTW, LINQ nhanh hơn trong việc phân loại so với các phương thức khung "gốc". – gdoron

12

Các thẳng nhất về phía trước, và hiệu quả nhất, sẽ chỉ đơn giản là vòng lặp thông qua các nhân vật trong chuỗi:

int cnt = 0; 
foreach (char c in test) { 
    if (c == '&') cnt++; 
} 

Bạn có thể sử dụng phần mở rộng LINQ để thực hiện một đơn giản hơn và gần như là phiên bản hiệu quả. Có nhiều hơn một chút trên không, nhưng nó vẫn còn đáng ngạc nhiên gần với vòng lặp trong hoạt động:

int cnt = test.Count(c => c == '&'); 

Sau đó là cũ Replace lừa, tuy nhiên đó là phù hợp hơn cho các ngôn ngữ nơi vòng lặp là vụng về (SQL) hoặc chậm (VBScript):

int cnt = test.Length - test.Replace("&", "").Length; 
+0

_surprisingly gần vòng lặp trong performance_ chỉ với haystacks khá nhỏ. – TaW

+0

@TaW: Tôi không thấy sự khác biệt đáng kể về tốc độ giữa các chuỗi ngắn và dài (1MB), nhưng vì một lý do nào đó có sự khác biệt lớn hơn trong chế độ x64 so với ở chế độ x86. – Guffa

+0

Tôi đã không kiểm tra phiên bản đếm char, nhưng số chuỗi linq chậm hơn và nhiều hơn nữa với chuỗi dài hơn và cuối cùng chết với một ngoại lệ oom. 1MB chưa phải là một vấn đề. – TaW

8

Ví dụ về chuỗi của bạn trông giống như phần chuỗi truy vấn của GET. Nếu vậy, lưu ý rằng HttpContext có một số trợ giúp cho bạn

int numberOfArgs = HttpContext.Current.QueryString.Count; 

Để biết thêm về những gì bạn có thể làm với QueryString, xem NameValueCollection

7

Dưới đây là cách hiệu quả nhất để có được số lượng trong tất cả các câu trả lời. Nhưng bạn sẽ nhận được một từ điển có chứa các cặp khóa-giá trị làm tiền thưởng.

string test = "key1=value1&key2=value2&key3=value3"; 

var keyValues = Regex.Matches(test, @"([\w\d]+)=([\w\d]+)[&$]*") 
        .Cast<Match>() 
        .ToDictionary(m => m.Groups[1].Value, m => m.Groups[2].Value); 

var count = keyValues.Count - 1; 
+8

haha, "cách không hiệu quả nhất", thích nó! – payo

+1

Đặt địa chỉ này là "mã-trolling" được Q & A gắn thẻ trên http://codegolf.stackexchange.com – Kroltan

Các vấn đề liên quan