Ich habe eine Verpflichtung , die relativ dunkel ist, aber es fühlt sich an wie es sollte möglich sein , die BCL verwenden.
Für den Kontext analysiere ich eine Datums- / Zeitzeichenfolge in Noda Time . Ich behalte einen logischen Cursor für meine Position innerhalb der Eingabezeichenfolge. Während die vollständige Zeichenfolge "3. Januar 2013" sein kann, befindet sich der logische Cursor möglicherweise auf "J".
Jetzt muss ich den Monatsnamen analysieren und ihn mit allen bekannten Monatsnamen für die Kultur vergleichen:
- Kulturbewusst
- Groß- und Kleinschreibung wird nicht berücksichtigt
- Nur von der Spitze des Cursors (nicht später; ich möchte sehen, ob der Cursor den Monatsnamen des Kandidaten "ansieht")
- Schnell
- ... und ich muss später wissen, wie viele Zeichen verwendet wurden
Der aktuelle Code dafür funktioniert im Allgemeinen mit CompareInfo.Compare. Es ist effektiv so (nur für den passenden Teil - es gibt mehr Code in der realen Sache, aber es ist nicht relevant für das Match):
internal bool MatchCaseInsensitive(string candidate, CompareInfo compareInfo)
{
return compareInfo.Compare(text, position, candidate.Length,
candidate, 0, candidate.Length,
CompareOptions.IgnoreCase) == 0;
}
Dies hängt jedoch davon ab, dass der Kandidat und die Region, die wir vergleichen, gleich lang sind. Meistens in Ordnung, in einigen besonderen Fällen jedoch nicht in Ordnung. Angenommen, wir haben so etwas wie:
// 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";
Jetzt wird mein Vergleich fehlschlagen. Ich könnte gebrauchen IsPrefix:
if (compareInfo.IsPrefix(text.Substring(position), candidate,
CompareOptions.IgnoreCase))
aber:
- Dafür muss ich einen Teilstring erstellen, den ich lieber vermeiden möchte. (Ich betrachte Noda Time als eine effektive Systembibliothek. Die Analyse der Leistung kann für einige Clients sehr wichtig sein.)
- Es sagt mir nicht, wie weit ich den Cursor danach bewegen soll
In Wirklichkeit vermute ich stark, dass dies nicht sehr oft vorkommt ... aber ich würde hier wirklich gerne das Richtige tun. Ich würde es auch wirklich gerne tun können, ohne Unicode-Experte zu werden oder es selbst zu implementieren :)
(Wird in Noda Time als Fehler 210 ausgelöst, falls jemand einer möglichen Schlussfolgerung folgen möchte.)
Ich mag die Idee der Normalisierung. Ich muss das im Detail auf a) Richtigkeit und b) Leistung überprüfen. Vorausgesetzt, ich kann es richtig machen, bin ich mir immer noch nicht sicher, ob es sich lohnt, alles zu ändern - so etwas wird im wirklichen Leben wahrscheinlich nie auftauchen, könnte aber die Leistung aller meiner Benutzer beeinträchtigen: (
Ich habe auch die BCL überprüft - was anscheinend auch nicht richtig funktioniert. Beispielcode:
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");
}
}
}
Wenn Sie den benutzerdefinierten Monatsnamen in "Bett" mit dem Textwert "bEd" ändern, wird dies in Ordnung analysiert.
Okay, noch ein paar Datenpunkte:
Die Kosten für die Verwendung
SubstringundIsPrefixsind erheblich, aber nicht schrecklich. Bei einem Beispiel von "Friday April 12 2013 20:28:42" auf meinem Entwicklungs-Laptop ändert sich die Anzahl der Analysevorgänge, die ich in einer Sekunde ausführen kann, von ungefähr 460 KB auf ungefähr 400 KB. Ich würde diese Verlangsamung lieber vermeiden, wenn es möglich ist, aber es ist nicht so schlimm.Normalisierung ist weniger machbar als ich dachte - weil sie in tragbaren Klassenbibliotheken nicht verfügbar ist. Ich könnte es möglicherweise nur für Nicht-PCL-Builds verwenden, sodass die PCL-Builds etwas weniger korrekt sind. Der Leistungstreffer beim Testen auf Normalisierung (
string.IsNormalized) reduziert die Leistung auf etwa 445.000 Anrufe pro Sekunde, mit denen ich leben kann. Ich bin mir immer noch nicht sicher, ob es alles tut, was ich brauche - zum Beispiel sollte ein Monatsname, der "ß" enthält, in vielen Kulturen mit "ss" übereinstimmen, glaube ich ... und Normalisierung macht das nicht.
textnicht zu lang sind, können Sie tun if (compareInfo.IndexOf(text, candidate, position, options) == position). msdn.microsoft.com/en-us/library/ms143031.aspx Aber wenn textes sehr lang ist, wird es viel Zeit verschwenden, darüber hinaus zu suchen, wo es nötig ist.
StringKlasse überhaupt in diesem Fall und verwendet eine Char[]direkt. Sie werden am Ende mehr Code schreiben, aber das passiert, wenn Sie hohe Leistung wünschen ... oder vielleicht sollten Sie in C ++ / CLI programmieren ;-)