Tôi có một yêu cầu tương đối mù mờ, nhưng có vẻ như nó sẽ có thể thực hiện được bằng cách sử dụng BCL.
Đối với ngữ cảnh, tôi đang phân tích cú pháp chuỗi ngày / giờ trong Noda Time . Tôi duy trì một con trỏ logic cho vị trí của tôi trong chuỗi đầu vào. Vì vậy, trong khi chuỗi hoàn chỉnh có thể là "3 tháng 1 năm 2013", con trỏ logic có thể ở 'J'.
Bây giờ, tôi cần phân tích cú pháp tên tháng, so sánh nó với tất cả các tên tháng đã biết cho văn hóa:
- Văn hóa nhạy cảm
- Không phân biệt chữ hoa chữ thường
- Chỉ từ điểm của con trỏ (không phải sau này; tôi muốn xem liệu con trỏ có đang "nhìn" tên tháng ứng cử viên hay không)
- Mau
- ... và tôi cần biết sau đó có bao nhiêu ký tự đã được sử dụng
Các mã hiện tại để làm điều này thường hoạt động, sử dụng CompareInfo.Compare
. Nó thực sự như thế này (chỉ dành cho phần khớp - có nhiều mã hơn trong thực tế, nhưng nó không liên quan đến phần khớp):
internal bool MatchCaseInsensitive(string candidate, CompareInfo compareInfo)
{
return compareInfo.Compare(text, position, candidate.Length,
candidate, 0, candidate.Length,
CompareOptions.IgnoreCase) == 0;
}
Tuy nhiên, điều đó phụ thuộc vào ứng viên và khu vực mà chúng tôi so sánh có cùng độ dài. Hầu hết thời gian đều tốt, nhưng không tốt trong một số trường hợp đặc biệt. Giả sử chúng ta có một cái gì đó như:
// U+00E9 is a single code point for e-acute
var text = "x b\u00e9d y";
int position = 2;
// e followed by U+0301 still means e-acute, but from two code points
var candidate = "be\u0301d";
Bây giờ so sánh của tôi sẽ thất bại. Tôi có thể sử dụng IsPrefix
:
if (compareInfo.IsPrefix(text.Substring(position), candidate,
CompareOptions.IgnoreCase))
nhưng:
- Điều đó đòi hỏi tôi phải tạo một chuỗi con, điều mà tôi thực sự muốn tránh. (Tôi đang xem Noda Time thực sự là một thư viện hệ thống; hiệu suất phân tích cú pháp cũng có thể quan trọng đối với một số khách hàng.)
- Nó không cho tôi biết bao xa để di chuyển con trỏ sau đó
Trong thực tế, tôi thực sự nghi ngờ điều này sẽ không xuất hiện thường xuyên ... nhưng tôi thực sự muốn làm điều đúng đắn ở đây. Tôi cũng thực sự muốn có thể làm điều đó mà không cần trở thành chuyên gia Unicode hoặc tự thực hiện nó :)
(Được phát triển thành lỗi 210 trong Noda Time, trong trường hợp bất kỳ ai muốn theo dõi bất kỳ kết luận cuối cùng nào.)
Tôi thích ý tưởng bình thường hóa. Tôi cần kiểm tra chi tiết điều đó để biết a) tính đúng đắn và b) hiệu suất. Giả sử tôi có thể làm cho nó hoạt động chính xác, tôi vẫn không chắc liệu nó có đáng để thay đổi hay không - đó là loại điều có thể sẽ không bao giờ thực sự xuất hiện trong đời thực, nhưng có thể ảnh hưởng đến hiệu suất của tất cả người dùng của tôi: (
Tôi cũng đã kiểm tra BCL - dường như cũng không xử lý việc này đúng cách. Mã mẫu:
using System;
using System.Globalization;
class Test
{
static void Main()
{
var culture = (CultureInfo) CultureInfo.InvariantCulture.Clone();
var months = culture.DateTimeFormat.AbbreviatedMonthNames;
months[10] = "be\u0301d";
culture.DateTimeFormat.AbbreviatedMonthNames = months;
var text = "25 b\u00e9d 2013";
var pattern = "dd MMM yyyy";
DateTime result;
if (DateTime.TryParseExact(text, pattern, culture,
DateTimeStyles.None, out result))
{
Console.WriteLine("Parsed! Result={0}", result);
}
else
{
Console.WriteLine("Didn't parse");
}
}
}
Thay đổi tên tháng tùy chỉnh thành chỉ "giường" với giá trị văn bản là "bEd" phân tích cú pháp tốt.
Được rồi, một vài điểm dữ liệu khác:
Chi phí sử dụng
Substring
vàIsPrefix
là đáng kể nhưng không kinh khủng. Trong một ví dụ về "Thứ sáu, ngày 12 tháng 4 năm 2013 20:28:42" trên máy tính xách tay phát triển của tôi, nó thay đổi số lượng hoạt động phân tích cú pháp mà tôi có thể thực hiện trong một giây từ khoảng 460 nghìn thành khoảng 400 nghìn. Tôi muốn tránh sự chậm lại đó nếu có thể, nhưng nó không quá tệ.Chuẩn hóa kém khả thi hơn tôi nghĩ - vì nó không có sẵn trong Thư viện lớp di động. Tôi có khả năng có thể sử dụng nó chỉ cho người không PCL xây dựng, cho phép PCL xây dựng được một chút ít chính xác. Hiệu suất đạt được của thử nghiệm chuẩn hóa (
string.IsNormalized
) làm giảm hiệu suất xuống còn khoảng 445K cuộc gọi mỗi giây, tôi có thể sống chung với nó. Tôi vẫn không chắc nó làm được mọi thứ tôi cần - ví dụ: tên tháng chứa "ß" phải khớp với "ss" trong nhiều nền văn hóa, tôi tin rằng ... và việc chuẩn hóa không làm được điều đó.
text
không quá dài, bạn có thể làm if (compareInfo.IndexOf(text, candidate, position, options) == position)
. msdn.microsoft.com/en-us/library/ms143031.aspx Nhưng nếu text
quá dài sẽ lãng phí rất nhiều thời gian để tìm kiếm ngoài nơi cần thiết.
String
lớp ở tất cả trong trường hợp này và sử dụng một Char[]
cách trực tiếp. Bạn sẽ kết thúc việc viết mã hơn, nhưng đó là những gì sẽ xảy ra khi bạn muốn hiệu suất cao ... hoặc có lẽ bạn nên được lập trình trong C ++ / CLI ;-)