J'ai une exigence qui est relativement obscure, mais j'ai l'impression que devrait être possible en utilisant la BCL.
Pour le contexte, je parsagerai une chaîne de date/heure en Heure de Noda . Je maintiens un curseur logique pour ma position dans la chaîne d'entrée. Ainsi, alors que la chaîne complète peut être "3 janvier 2013", le curseur logique peut se trouver au "J".
Maintenant, je dois analyser le nom du mois, en le comparant à tous les noms de mois connus pour la culture :
- Sensible à la culture
- Insensiblement au cas par cas
- Juste à partir du point du curseur (pas plus tard ; je veux voir si le curseur "regarde" le nom du mois du candidat)
- Rapidement
- ... et j'ai besoin de savoir ensuite combien de caractères ont été utilisés.
El code actuel pour ce faire fonctionne généralement, en utilisant CompareInfo.Compare
. C'est en fait comme ceci (juste pour la partie correspondance - il y a plus de code dans la vraie chose, mais ce n'est pas pertinent pour la correspondance) :
internal bool MatchCaseInsensitive(string candidate, CompareInfo compareInfo)
{
return compareInfo.Compare(text, position, candidate.Length,
candidate, 0, candidate.Length,
CompareOptions.IgnoreCase) == 0;
}
Toutefois, cela suppose que le candidat et la région que nous comparons aient la même longueur. C'est bien la plupart du temps, mais no bien dans certains cas particuliers. Supposons que nous ayons quelque chose comme :
// 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";
Maintenant, ma comparaison va échouer. Je pourrais utiliser IsPrefix
:
if (compareInfo.IsPrefix(text.Substring(position), candidate,
CompareOptions.IgnoreCase))
mais :
- Cela m'oblige à créer une sous-chaîne, ce que je préfère éviter. (Je considère Noda Time comme étant effectivement une bibliothèque système ; les performances d'analyse syntaxique peuvent très bien être importantes pour certains clients).
- Il ne me dit pas jusqu'où avancer le curseur ensuite.
En réalité, je soupçonne fortement que cela ne se produira pas très souvent... mais j'aimerais vraiment... comme pour faire la bonne chose ici. J'aimerais aussi pouvoir le faire sans avoir à devenir un expert d'Unicode ou à le mettre en œuvre moi-même :)
(soulevée en tant que bug 210 en temps Noda, au cas où quelqu'un voudrait suivre une éventuelle conclusion).
J'aime l'idée de normalisation. Je dois vérifier cela en détail pour a) l'exactitude et b) les performances. En supposant que je peut de le faire fonctionner correctement, je ne suis toujours pas sûr qu'il vaille la peine de le changer - c'est le genre de chose qui sera probablement jamais en réalité, mais pourrait nuire aux performances de tous mes utilisateurs :(
J'ai également vérifié la BCL, qui ne semble pas non plus gérer ce problème correctement. Exemple de code :
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");
}
}
}
Changer le nom du mois personnalisé en "bed" avec une valeur de texte de "bEd" est très bien interprété.
Ok, quelques points de données supplémentaires :
-
Le coût de l'utilisation de
Substring
yIsPrefix
est significatif mais pas horrible. Sur un échantillon de "Friday April 12 2013 20:28:42" sur mon ordinateur portable de développement, cela fait passer le nombre d'opérations d'analyse que je peux exécuter en une seconde d'environ 460K à environ 400K. Je préférerais éviter ce ralentissement si possible, mais ce n'est pas le cas. trop mauvais. -
La normalisation est moins réalisable que je ne le pensais, car elle n'est pas disponible dans les bibliothèques de classes portables. Je pourrais potentiellement l'utiliser juste pour les constructions non-PCL, permettant aux constructions PCL d'être un peu moins correctes. L'impact sur les performances des tests de normalisation (
string.IsNormalized
) ramène les performances à environ 445 000 appels par seconde, ce qui me convient. Je ne suis toujours pas sûr qu'il fasse tout ce dont j'ai besoin - par exemple, un nom de mois contenant "ß" devrait correspondre à "ss" dans de nombreuses cultures, je crois... et la normalisation ne le fait pas.