2010-07-29 30 views
2

J'ai besoin de code pour une méthode Replace insensible à la casse pour la classe StringBuilder. Le code devrait fonctionner avec le StringBuilder existant. Une implémentation de méthode d'extension serait bien.J'ai besoin d'une méthode Replace insensible à la casse qui fonctionne avec la classe StringBuilder

Après comment je prévois d'utiliser la méthode:

[TestMethod] 
    public void StringBuilder_Replace_TTD() { 

     StringBuilder oRequestText = new StringBuilder(File.ReadAllText("Customer.xml")); 

     Customer oCustomer = new Customer(null); 

     foreach (FieldIndex iField in Enum.GetValues(typeof(FieldIndex))) { 

      oRequestText.Replace("{" iField.ToString() + "}", oCustomer[iField]); 

     } 

     Debug.WriteLine(oRequestText.ToString()); 
    } 
+0

Comment remplacer un travail insensible à la casse exactement? Faut-il remplacer Foo par Bar et FOO avec BAR? –

+0

@Mark: Je pense que l'on s'attend à ce que l'étape de "recherche" dans le remplacement soit insensible à la casse. La valeur remplacée serait quel que soit le texte de remplacement. – LBushkin

+0

Correct, je veux remplacer "foo", quel que soit le cas, avec "BAR". – AMissico

Répondre

2

De: http://blogs.msdn.com/b/btine/archive/2005/03/22/400667.aspx

string Replace(string expr, string find, string repl, bool bIgnoreCase) 
{ 
// Get input string length 
     int exprLen = expr.Length; 
     int findLen = find.Length; 

     // Check inputs  
     if(0 == exprLen || 0 == findLen || findLen > exprLen)  
       return expr; 

     // Use the original method if the case is required  
     if(!bIgnoreCase) 
       return expr.Replace(find, repl); 

     StringBuilder sbRet = new StringBuilder(exprLen); 

     int pos = 0;    
     while(pos + findLen <= exprLen)  
     {  
       if(0 == string.Compare(expr, pos, find, 0, findLen, bIgnoreCase))  
       {  
        // Add the replaced string  
        sbRet.Append(repl);  
        pos += findLen;  
        continue;  
       } 

       // Advance one character  
       sbRet.Append(expr, pos++, 1);  
     } 

     // Append remaining characters  
     sbRet.Append(expr, pos, exprLen-pos); 

     // Return string  
     return sbRet.ToString();  
} 
+1

Dommage qu'il n'y ait pas de cas de test ... Je suis hésitant à upvoter un morceau de code si compliqué sans aucune indication que cela fonctionne. En outre, cela semble être O (n^2). Ne serait-il pas préférable d'utiliser 'IndexOf' avec' StringComparison.CurrentCultureIgnoreCase' par exemple? –

+0

Utilise une chaîne et renvoie une chaîne.Je veux une méthode qui fonctionne avec un StringBuilder, pendant le remplacement sans créer de nouvelles chaînes ou de nouveaux constructeurs de chaînes. – AMissico

+0

@Mark - ça vient de MSDN, donc ça veut dire que _has_ a raison, n'est-ce pas? :) @AMissico - OK - maintenant je vois ce que vous voulez dire ... laissez-moi essayer quelques petites choses. – NinjaCat

3

StringBuilder ne prend pas en charge l'utilisation d'un IComparer lorsque le texte de recherche/remplacement (en fait, il y a pas de support de recherche du tout). Vous pouvez essayer de lancer une version caractère par caractère, mais cela sera compliqué et peut encore mal fonctionner. En fonction de votre cas d'utilisation, je suggérerais d'utiliser une chaîne plutôt que StringBuilder, et d'utiliser string.IndexOf() pour localiser les positions dans la chaîne d'entrée où vous allez faire le remplacement - qui supporte la recherche insensible à la casse. Une fois que vous avez localisé toutes les régions de remplacement, créez un StringBuilder puis copiez chaque région en remplaçant le texte trouvé par les valeurs de remplacement souhaitées.

EDIT: Vous envisagez probablement d'utiliser le remplacement avec un StringBuilder pour éviter d'allouer des chaînes supplémentaires et d'obtenir le coup de performance pour ce faire. Cependant, en remplaçant le texte par, le tampon d'un StringBuilder pourrait en fait être plus cher - en particulier si les chaînes de remplacement sont de longueur différente de la chaîne source qu'elles remplacent. Chaque remplacement nécessite que les caractères soient décalés vers l'avant ou vers l'arrière selon que le texte de remplacement est plus court ou plus long. L'exécution de bloc de mémoire se déplace comme cela sera coûteux.

+0

J'ai une méthode pour la chaîne, mais je veux pour StringBuilder parce que je vais faire plus de 40 remplacements. Je préférerais ne pas créer plus de 40 chaînes. – AMissico

+2

@AMissico: Je ne propose pas que vous fassiez cela. Je suggère que vous * démarrez * avec une chaîne régulière afin de profiter des méthodes de recherche insensible à la casse. Une fois que vous avez localisé les * index et les longueurs * de toutes les sous-chaînes à remplacer, vous copiez sélectivement de la chaîne d'origine dans un StringBuilder et effectuez un remplacement pour chaque sous-chaîne trouvée. Il est également plus efficace que le remplacement dans un StringBuilder car il ne nécessitera pas * de déplacer des blocs de texte *, ce qui se produirait si les remplacements avaient une longueur différente de celle du texte qu'ils remplacent. – LBushkin

+0

Je crois comprendre ce que vous suggérez. Pourtant, je ne vois pas comment éviter de créer la chaîne 40+ pour trouver les * index et les longueurs * pour chacun des membres enum. La performance n'est pas ma principale préoccupation. Pour ce cas précis, je suis plus intéressé par le code propre et le code prêt à la production. – AMissico

0

Dans votre exemple, vous voulez faire (dans le code pseudo):

StringBuilder oRequestText = ...; 
For all fields do replace on oRequestText; 
Debug.WriteLine(oRequestText.ToString()); 

Puisque vous n'êtes pas réellement en utilisant le StringBuilder après cela, il n'y a pas de différence fonctionnelle avec

StringBuilder oRequestText = ...; 
string strRequest = oRequestText.ToString(); 
For all fields do replace on strRequest; 
Debug.WriteLine(strRequest); 

La normale remplacer les fonctions pour les chaînes devrait facilement supporter ce que vous voulez faire.

Je suppose que dans votre situation réelle vous voulez utiliser à nouveau le StringBuilder. Mais il est probablement encore plus facile de faire un .ToString(), remplacer sur la chaîne, puis recharger le StringBuilder avec la chaîne.

0

J'utilise la méthode RegEx remplacer, mais cela signifie la conversion d'un StribgBuilder à une chaîne

oRequestText = new StringBuilder(Regex.Replace(oRequestText.ToString(), "{" iField.ToString() + "}", oCustomer[iField], RegexOptions.IgnoreCase)));