56 votes

someString.IndexOf (someString) renvoie 1 au lieu de 0 sous .NET 4

Nous avons récemment mis à jour l'ensemble de nos projets .NET 3.5 .NET 4. J'ai rencontré une étrange question à l'égard string.IndexOf().

Mon code n'est évidemment quelque chose de légèrement différent, mais dans le processus d'enquêter sur la question, j'ai trouvé que l'appelant IndexOf() sur une corde avec lui-même retourné 1 au lieu de 0. En d'autres termes:

string text = "\xAD\x2D";          // problem happens with "­-dely N.China", too;
int index = text.IndexOf(text);    // see update note below.

M'a donné un indice de 1, au lieu de 0. Un couple de choses à noter à propos de ce problème:

  • Les problèmes semblent être liées à ces traits d'union (le premier caractère est un caractère Unicode doux trait d'union, le deuxième est un habitué de trait d'union).

  • J'ai vérifié, cela ne se produit pas .NET 3.5, mais n'en .NET 4.

  • Modification de l' IndexOf() faire un ordinal comparer résout le problème, pour une raison que le premier caractère est ignoré par défaut est IndexOf.

Personne ne sait pourquoi cela se produit?

MODIFIER

Désolé les gars, faites un peu de tout ça sur le post original et a obtenu le caché tableau de bord en deux fois. J'ai mis à jour la chaîne, ce qui devrait indice de rendement de 1 au lieu de 2, aussi longtemps que vous le collez dans le bon éditeur.

Mise à jour:

Changé le problème initial de la chaîne à un endroit où chaque personnage est clairement visible (à l'aide d'échappement). Cela simplifie la question un peu.

32voto

CodeCaster Points 38181

Votre chaîne de deux caractères: un doux trait d'union (point de code Unicode 173) et un trait d'union (point de code Unicode 45).

Wiki: Selon le standard Unicode, un léger trait d'union n'est pas affiché si la ligne n'est pas cassé à ce point.

Lors de l'utilisation d' "\xAD\x2D".IndexOf("\xAD\x2D") .NET 4, il semble ignorer que vous êtes à la recherche pour le soft trait d'union, un retour de l'indice de départ est de 1 (l'indice de \x2D). Dans .NET 3.5, cela renvoie 0.

Plus de plaisir, si vous exécutez ce code (donc quand seulement à la recherche pour le soft trait d'union):

string text = "\xAD\x2D";
string shy = "\xAD";
int i1 = text.IndexOf(shy);

ensuite, i1 devient 0, quel que soit le .NET version utilisée. Le résultat de l' text.IndexOf(text); varie, en effet, qui d'un coup d'oeil ressemble à un bug pour moi.

Aussi loin que je puisse remonter à travers le cadre, plus .NET versions utilisent un InternalCall d' IndexOfString() (je ne peux pas savoir à qui les appels de l'API qui va), tandis qu'à partir .NET 4 un QCall d' InternalFindNLSStringEx() est faite, ce qui à son tour appelle FindNLSStringEx().

La question (je ne peux vraiment pas comprendre si c'est prévu comportement) en effet se produit lors de l'appel d' FindNLSStringEx:

LPCWSTR lpStringSource = L"\xAD\x2D";
LPCWSTR lpStringValue = L"\xAD";

int length;

int i = FindNLSStringEx(
    LOCALE_NAME_SYSTEM_DEFAULT,
    FIND_FROMSTART,
    lpStringSource,
    -1,
    lpStringValue,
    -1,
    &length,
    NULL,
    NULL,
    1);

Console::WriteLine(i);

i = FindNLSStringEx(
    LOCALE_NAME_SYSTEM_DEFAULT,
    FIND_FROMSTART,
    lpStringSource,
    -1,
    lpStringSource,
    -1,
    &length,
    NULL,
    NULL,
    1);

Console::WriteLine(i);

Console::ReadLine();

Tirages de 0 et de 1. Notez que length, un paramètre indiquant la longueur de la trouvé de chaîne, est de 0 après le premier appel et 1 après la seconde; la douceur du trait d'union est comptabilisé comme ayant une longueur de 0.

La solution de contournement consiste à utiliser text.IndexOf(text, StringComparison.OrdinalIgnoreCase);, comme vous l'avez remarqué. Ce qui fait un QCall d' InternalCompareStringOrdinalIgnoreCase() qui appelle à son tour FindStringOrdinal(), qui renvoie 0 pour les deux cas.

20voto

Ria Points 5743

Il semble être un bug .NET4, et de nouvelles modifications revenue en .NET4 Beta1 à la version précédente même que .NET 2.0/3.0/3.5.

Ce qui est Nouveau dans la BCL .NET 4.0 CTP (MSDN blogs):

Chaîne de Modifications de Sécurité .NET 4

Le défaut partiel de correspondance des surcharges sur le Système.Chaîne (StartsWith, EndsWith, IndexOf, et LastIndexOf) ont été modifiés pour la culture-agnostique (ordinale) par défaut.

Ce changement a affecté le comportement de l' String.IndexOf méthode par changement d'effectuer un nombre ordinal (octet-par-octet) comparaison par défaut seront modifiés pour utiliser l' CultureInfo.InvariantCulture au lieu de CultureInfo.CurrentCulture.

Mise à JOUR pour .NET 4 Beta 1

Pour maintenir un niveau élevé de compatibilité entre les deux .NET 4 et les versions précédentes, nous avons décidé de revenir sur ce changement. Le comportement de la Chaîne de caractères par défaut de la reconnaissance partielle des surcharges et String et Char ToUpper et ToLower méthodes se comportent de la même façon .NET 2.0/3.0/3.5. Le changement dans le comportement d'origine est présent dans .NET 4 Beta 1.


Pour corriger cela, modifiez la chaîne de la méthode de comparaison à une surcharge qui accepte de l' System.StringComparison énumération comme un paramètre, et de spécifier Ordinal ou OrdinalIgnoreCase.

// string contains 'unicode dash' \x2D
string text = "\xAD\x2D"; 

// woks in .NET 2.0/3.0/3.5 and .NET 4 Beta 1 and later
// but seems be buggy in .NET 4 because of 'culture-sensitive' comparison        
int index = text.IndexOf(text); 

// fixed version
index = text.IndexOf(text, StringComparison.Ordinal); 

0voto

Richard Points 54016

À partir de la documentation (mon emphase):

Cette méthode effectue un mot (sensible à la casse et sensible à la culture,de recherche) à l'aide de la culture actuelle.

C'est à dire. des code-points seront traités comme des égaux.

Qu'advient-il si vous utilisez une surcharge qui prend un StringComparison de la valeur et de transmettre StringComparison.Ordinal afin d'éviter la culturelle des dépendances?

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X