У мене є вимога , яке є відносно неясним, але він відчуває , як це повинно бути можливо з допомогою BCL.
Для контексту я аналізую рядок дати / часу в Noda Time . Я підтримую логічний курсор для свого положення у вхідному рядку. Таким чином, хоча повна рядок може бути "3 січня 2013 року", логічний курсор може бути на "J".
Тепер мені потрібно проаналізувати назву місяця, порівнявши її з усіма відомими культовими назвами місяців:
- Культурно-чутливо
- Випадок безчутливий
- Просто з точки курсору (не пізніше; я хочу дізнатися, чи курсор "дивиться" ім'я місяця кандидата)
- Швидко
- ... і мені потрібно знати після цього, скільки символів було використано
Поточний код , щоб зробити це , як правило працює, використовуючи CompareInfo.Compare
. Це ефективно так (тільки для відповідної частини - у реальній справі більше коду, але це не стосується матчу):
internal bool MatchCaseInsensitive(string candidate, CompareInfo compareInfo)
{
return compareInfo.Compare(text, position, candidate.Length,
candidate, 0, candidate.Length,
CompareOptions.IgnoreCase) == 0;
}
Однак це залежить від кандидата та регіону, який ми порівнюємо, однакової довжини. Штрафують більшу частину часу, але в деяких особливих випадках не штрафують. Припустимо, у нас є щось на кшталт:
// 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";
Зараз моє порівняння провалиться. Я можу використовувати IsPrefix
:
if (compareInfo.IsPrefix(text.Substring(position), candidate,
CompareOptions.IgnoreCase))
але:
- Це вимагає, щоб я створив підрядку, якої я б дуже хотів уникати. (Я переглядаю Noda Time настільки ефективно, як системна бібліотека; аналіз ефективності може бути важливим для деяких клієнтів.)
- Це не говорить мені, як далеко рухати курсор згодом
Насправді я дуже підозрюю, що це не дуже часто виникає ... але я дуже хотів би зробити це правильно. Я також дуже хотів би це зробити, не ставши експертом Unicode або не реалізуючи це сам :)
(Визначено як помилка 210 за Noda Time, якщо хтось хоче виконати будь-який можливий висновок.)
Мені подобається ідея нормалізації. Мені потрібно детально перевірити наявність а) правильності та б) виконання. Припускаючи, що я можу змусити його працювати правильно, я все ще не впевнений, як варто було б змінитись над усім - це та річ, яка, ймовірно, ніколи не з’явиться в реальному житті, але може зашкодити роботі всіх моїх користувачів: (
Я також перевірив BCL - який, здається, не справляється з цим належним чином. Приклад коду:
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");
}
}
}
Змінення користувацької назви місяця на просто "ліжко" із текстовим значенням "bEd" добре аналізує.
Гаразд, ще кілька точок даних:
Вартість використання
Substring
таIsPrefix
значна, але не жахлива. На вибірці "П’ятниця 12 квітня 2013 20:28:42" на моєму ноутбуці для розробки він змінює кількість операцій розбору, які я можу виконати за секунду, приблизно від 460K до приблизно 400K. Я б скоріше уникав цього уповільнення, якщо це можливо, але це не дуже погано.Нормалізація менш здійсненна, ніж я думав - тому що вона не доступна в бібліотеках портативних класів. Я потенційно міг би використовувати його лише для збірок, що не належать до PCL, дозволяючи збірці PCL бути менш правильними. Результативність тестування на нормалізацію (
string.IsNormalized
) знижує продуктивність приблизно до 445 КЛ в секунду, з чим я можу жити. Я все ще не впевнений, що він робить все, що мені потрібно - наприклад, назва місяця, що містить "ß", повинна відповідати "ss" у багатьох культурах, я вважаю ... і нормалізація цього не робить.
text
не занадто довгий, ви можете зробити if (compareInfo.IndexOf(text, candidate, position, options) == position)
. msdn.microsoft.com/en-us/library/ms143031.aspx Але якщо text
це дуже довго, це витратить багато часу на пошук за межами, де це потрібно.
String
класу взагалі в цьому випадку та використовуйте Char[]
безпосередньо. Ви закінчите писати більше коду, але це те, що відбувається, коли ви хочете отримати високу продуктивність ... або, можливо, вам слід програмувати на C ++ / CLI ;-)