比較的あいまいな要件がありますが、BCLを使用して可能であると思われます。
コンテキストとして、日付/時刻文字列を野田時間で解析しています。入力文字列内の自分の位置に論理カーソルを保持しています。したがって、完全な文字列は「2013年1月3日」である可能性がありますが、論理カーソルは「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))
だが:
- そのため、部分文字列を作成する必要がありますが、これは避けたいと思います。(私は野田時間を効果的にシステムライブラリと見なしています。一部のクライアントにとっては、パフォーマンスの解析が重要になる場合があります。)
- 後でカーソルをどれだけ進めるかはわかりません
現実には、私は強く、これは非常に頻繁に出てくるではないだろう疑う...しかし、私は本当にしたいのように、ここで正しいことを行うために。また、Unicodeの専門家になったり、自分で実装したりせずにできるようになりたいです:)
(最終的に結論を出したい場合に備えて、野田時間のバグ210として発生します。)
正規化の考え方が好きです。a)正確性およびb)パフォーマンスについて詳細に確認する必要があります。私がそれを正しく機能させることができると仮定しても、それがすべてを交換する価値があるかどうかはまだわかりません-これは実際には実際には決して起こらないようなものですが、すべてのユーザーのパフォーマンスを損なう可能性があります: (
また、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」のテキスト値を持つ「bed」に変更すると、正常に解析されます。
さて、さらにいくつかのデータポイント:
使用してのコスト
Substring
とIsPrefix
有意であるが恐ろしいではありません。開発用ラップトップの「金曜日2013年4月12日20:28:42」のサンプルでは、1秒間に実行できる解析操作の数が約460Kから約400Kに変更されています。可能な場合はそのような減速を回避したいのですが、それほど悪くはありません。正規化は思ったよりも実行可能ではありません。ポータブルクラスライブラリでは利用できないためです。PCL以外のビルドにのみ使用できる可能性があるため、PCLビルドの精度が少し低くなります。正規化テスト(
string.IsNormalized
)のパフォーマンスヒットにより、パフォーマンスは1秒あたり約445Kコールに低下します。私はまだそれが私が必要とするすべてを実行するかどうかわかりません-たとえば、「ß」を含む月の名前は多くの文化で「ss」と一致するはずです...そして正規化はそれを行いません。
text
が長すぎなければ、あなたはそうすることができますif (compareInfo.IndexOf(text, candidate, position, options) == position)
。msdn.microsoft.com/en-us/library/ms143031.aspx しかし、text
非常に長い場合は、必要な場所を超えて検索することに多くの時間を費やすことになります。
String
クラスをまったく使用せずに、Char[]
直接使用するだけです。あなたはより多くのコードを書くことになりますが、それはあなたが高パフォーマンスが欲しいときに起こることです...あるいは多分あなたはC ++ / CLIでプログラミングするべきです;-)