Ich habe eine Anforderung, die relativ obskur ist, aber es fühlt sich an wie sollte mit dem BCL möglich sein.Wie kann ich eine kultursensitive "Starts mit" -Operation aus der Mitte einer Zeichenfolge durchführen?
Für Kontext, ich analysiere eine Datum/Uhrzeit Zeichenfolge in Noda Time. Ich pflege einen logischen Cursor für meine Position innerhalb der Eingabezeichenfolge. Während also die vollständige Zeichenfolge "3. Januar 2013" sein kann, befindet sich der logische Cursor möglicherweise am "J".
Nun, ich brauche den Monatsnamen zu analysieren, es gegen alle bekannten Monatsnamen für die Kultur zu vergleichen:
- Kultur sensitiv
- Case-unsensibel
- Gerade unter dem Aspekt der Cursor (nicht später, ich sehen will, wenn die Cursor des Kandidaten Monatsnamen „auf der Suche“)
- schnell
- ... und ich muß danach wissen, wie viele Zeichen verwendet wurden
Die current code dies zu tun funktioniert in der Regel mit CompareInfo.Compare
. Es ist effektiv wie folgt aus (nur für die passende Teil - es gibt mehr Code in die reale Sache, aber es ist auf das Spiel nicht relevant):
internal bool MatchCaseInsensitive(string candidate, CompareInfo compareInfo)
{
return compareInfo.Compare(text, position, candidate.Length,
candidate, 0, candidate.Length,
CompareOptions.IgnoreCase) == 0;
}
jedoch, dass wir die gleichen Vergleich der Kandidaten und die Region verlässt sich sein Länge. Feine die meiste Zeit, aber nicht in einigen Sonderfällen gut. Angenommen, wir haben 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 konnte IsPrefix
verwenden:
if (compareInfo.IsPrefix(text.Substring(position), candidate,
CompareOptions.IgnoreCase))
aber:
- Das hat mich erfordert einen Teil zu erstellen, die ich würde wirklich lieber vermeiden. (Ich sehe Noda Zeit als effektiv eine Systembibliothek,. Leistung Parsen gut zu einigen Kunden wichtig sein kann)
- Es gefällt mir nicht sagen, wie weit Sie die Cursor voran danach
In Wirklichkeit I stark vermuten, dass dies nicht sehr oft kommen wird ... aber ich würde wirklich wie, um das Richtige hier zu tun. Ich würde auch gerne in der Lage sein, es zu tun wirklich ohne einen Unicode-Experten zu werden oder es selbst Umsetzung :)
(Raised als bug 210 in Noda Zeit, jemand im Fall will jeden möglichen Abschluss folgen.)
Ich mag die Idee der Normalisierung. Ich muss das genau überprüfen für a) Korrektheit und b) Leistung.Vorausgesetzt, ich kann machen es richtig funktionieren, bin ich immer noch nicht sicher, ob es wert wäre, über alle zu ändern - es ist die Art von Sache, die wahrscheinlich im wirklichen Leben kommen wird, aber könnte die Leistung von verletzen alle meine Benutzer :(
ich habe auch geprüft, die BCL - die diesen richtig entweder nicht zu handhaben scheinen 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");
}
}
}
den benutzerdefinierten Monatsnamen mit einem nur „Bett“ ändern. Textwert von "bEd" pariert fein.
Okay, ein paar mehr Datenpunkte:
Die Kosten
Substring
undIsPrefix
der Verwendung ist signifikant, aber nicht schrecklich. Auf einer Probe von "Freitag, den 12. April 2013, 20:28:42" auf meinem Entwicklungs-Laptop ändert sich die Anzahl der Parse-Operationen, die ich in einer Sekunde ausführen kann, von ungefähr 460 K bis ungefähr 400 K. Ich würde diese Verlangsamung lieber vermeiden, aber es ist nicht zu schlecht.Normalisierung ist weniger durchführbar, als ich dachte - weil sie nicht in Portable Class Libraries verfügbar ist. Ich könnte es möglicherweise verwenden nur für Nicht-PCL-Builds, so dass die PCL-Builds ein wenig weniger korrekt sein. Der Performance-Hit des Tests für die Normalisierung (
string.IsNormalized
) nimmt die Leistung auf etwa 445K Anrufe pro Sekunde herunter, womit 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 "ss" entsprechen, glaube ich ... und normalisieren tut das nicht. > Ein/viele casemappings erste und getrennt von der Handhabung unterschiedlicher Normalisierungsformen -
Während ich Ihren Wunsch verstehe, den Leistungseinbruch beim Erstellen eines Teilstrings zu vermeiden, könnte es das Beste sein, dies zu tun, aber früher im Spiel, indem Sie alles auf eine gewählte Unicode-Normalisierungsform FIRST verschieben und dann wissen, Nach-Punkt ". Wahrscheinlich D-Form. – IDisposable
@IDisposable: Ja, ich habe mich darüber gewundert. Natürlich kann ich die Monatsnamen selbst vorher normalisieren. Zumindest kann ich die Normalisierung nur einmal machen. Ich frage mich, ob die Normalisierungsprozedur prüft, ob zuerst etwas getan werden muss. Ich habe nicht viel Erfahrung in der Normalisierung - definitiv eine Möglichkeit, in die ich schauen kann. –
Wenn Ihr 'text' nicht zu lang ist, können Sie' if (compareInfo.IndexOf (text, candidate, position, options) == position) '. http://msdn.microsoft.com/en-us/library/ms143031.aspx Aber wenn "Text" sehr lang ist, wird das eine Menge Zeit verschwenden, die über das hinausgeht, wo es benötigt wird. –