string sentence = "We know it contains 'camel' Word.";
// Camel can be in different cases:
string s1 = "CAMEL";
string s2 = "CaMEL";
string s3 = "CAMeL";
// ...
string s4 = "Camel";
// ...
string s5 = "camel";
Comment remplacer "chameau" dans la phrase par "cheval" malgré que string.Replace
ne supporte pas ignoreCase
sur la chaîne de gauche?
Utilisez une expression régulière:
var regex = new Regex( "camel", RegexOptions.IgnoreCase );
var newSentence = regex.Replace( sentence, "horse" );
Bien sûr, cela correspondra également aux mots contenant chameau, mais ce n'est pas clair si vous le voulez ou non.
Si vous avez besoin de correspondances exactes, vous pouvez utiliser un MatchEvaluator personnalisé.
public static class Evaluators
{
public static string Wrap( Match m, string original, string format )
{
// doesn't match the entire string, otherwise it is a match
if (m.Length != original.Length)
{
// has a preceding letter or digit (i.e., not a real match).
if (m.Index != 0 && char.IsLetterOrDigit( original[m.Index - 1] ))
{
return m.Value;
}
// has a trailing letter or digit (i.e., not a real match).
if (m.Index + m.Length != original.Length && char.IsLetterOrDigit( original[m.Index + m.Length] ))
{
return m.Value;
}
}
// it is a match, apply the format
return string.Format( format, m.Value );
}
}
Utilisé avec l'exemple précédent pour envelopper la correspondance dans une étendue en tant que:
var regex = new Regex( highlightedWord, RegexOptions.IgnoreCase );
foreach (var sentence in sentences)
{
var evaluator = new MatchEvaluator( match => Evaluators.Wrap( match, sentence, "<span class='red'>{0}</span>" ) );
Console.WriteLine( regex.Replace( sentence, evaluator ) );
}
Ajoutez une méthode d'extension pour que string fasse l'affaire:
Usage:
string yourString = "TEXTTOREPLACE";
yourString.Replace("texttoreplace", "Look, I Got Replaced!", StringComparison.OrdinalIgnoreCase);
Code:
using System;
using System.Collections.Generic;
using System.IO;
public static class Extensions
{
public static string Replace(this string source, string oldString, string newString, StringComparison comp)
{
int index = source.IndexOf(oldString, comp);
// Determine if we found a match
bool MatchFound = index >= 0;
if (MatchFound)
{
// Remove the old text
source = source.Remove(index, oldString.Length);
// Add the replacemenet text
source = source.Insert(index, newString);
}
// recurse for multiple instances of the name
if (source.IndexOf(oldString, comp) != -1)
{
source = Replace(source, oldString, newString, comp);
}
return source;
}
}
Voici une méthode d'extension utilisant StringComparison, à l'aide de string.IndexOf:
[Pure]
public static string Replace(this string source, string oldValue, string newValue, StringComparison comparisonType)
{
if (source.Length == 0 || oldValue.Length == 0)
return source;
var result = new System.Text.StringBuilder();
int startingPos = 0;
int nextMatch;
while ((nextMatch = source.IndexOf(oldValue, startingPos, comparisonType)) > -1)
{
result.Append(source, startingPos, nextMatch - startingPos);
result.Append(newValue);
startingPos = nextMatch + oldValue.Length;
}
result.Append(source, startingPos, source.Length - startingPos);
return result.ToString();
}
Btw, voici également une méthode similaire Contains prenant également un StringComparison:
[Pure]
public static bool Contains(this string source, string value, StringComparison comparisonType)
{
return source.IndexOf(value, comparisonType) >= 0;
}
Quelques tests:
[TestFixture]
public class ExternalTests
{
private static string[] TestReplace_args =
{
"ab/B/c/ac",
"HELLO World/Hello/Goodbye/Goodbye World",
"Hello World/world/there!/Hello there!",
"hello WoRlD/world/there!/hello there!",
"///",
"ab///ab",
"/ab/cd/",
"a|b|c|d|e|f/|//abcdef",
"a|b|c|d|e|f|/|/:/a:b:c:d:e:f:",
};
[Test, TestCaseSource("TestReplace_args")]
public void TestReplace(string teststring)
{
var split = teststring.Split("/");
var source = split[0];
var oldValue = split[1];
var newValue = split[2];
var result = split[3];
Assert.That(source.Replace(oldValue, newValue, StringComparison.OrdinalIgnoreCase), Is.EqualTo(result));
}
}
Voici ma méthode d'extension, qui combine les actions de Tom Beech , avec le caractère récursif de sntbob , et une correction plus nette du bogue signalé par ksun .
Code:
public static string Replace(this string source, string oldString,
string newString, StringComparison comparison)
{
int index = source.IndexOf(oldString, comparison);
while (index > -1)
{
source = source.Remove(index, oldString.Length);
source = source.Insert(index, newString);
index = source.IndexOf(oldString, index + newString.Length, comparison);
}
return source;
}
Usage:
string source = "banana";
Console.WriteLine(source.Replace("AN", "banana", StringComparison.OrdinalIgnoreCase));
Résultat:
bbananabananaa
Et si vous voulez toujours que la nature récursive soit optionnelle:
Code:
public static string Replace(this string source, string oldString,
string newString, StringComparison comparison,
bool recursive = true)
{
int index = source.IndexOf(oldString, comparison);
while (index > -1)
{
source = source.Remove(index, oldString.Length);
source = source.Insert(index, newString);
if (!recursive)
{
return source;
}
index = source.IndexOf(oldString, index + newString.Length, comparison);
}
return source;
}
Usage:
string source = "banana";
Console.WriteLine(source.Replace("AN", "banana", StringComparison.OrdinalIgnoreCase, false));
Résultat:
bbananaana
Utiltize StringComparison
en raison de sa facilité OrdinalIgnoreCase
string sentence = "We know it contains 'camel' Word.";
string wordToFind = "camel";
string replacementWord = "horse";
int index = sentence.IndexOf(wordToFind , StringComparison.OrdinalIgnoreCase)
// Did we match the Word regardless of case
bool match = index >= 0;
// perform the replace on the matched Word
if(match) {
sentence = sentence.Remove(index, wordToFind.Length)
sentence = sentence.Insert(index, replacementWord)
}
Ce serait bien si la classe C # String avait une méthode ignoreCase()
comme Java.
Vous pouvez également utiliser String.IndexOf
http://msdn.Microsoft.com/en-us/library/system.string.indexof.aspx
Vous obtiendrez peut-être de meilleures performances en procédant de cette façon qu'avec RegExpressions (je les abhorre car elles ne sont pas intuitives et faciles à bousiller, bien que cet appel de fonction .Net abstraite le RegEx réellement désordonné, erreur), mais cela ne vous concerne probablement pas; les ordinateurs sont vraiment rapides ces jours-ci, non? :) La surcharge pour IndexOf qui prend un objet StringComparison vous permet d'ignorer éventuellement la casse et, comme IndexOf renvoie la première occurrence à une position spécifiée, vous devrez coder une boucle pour traiter une chaîne comportant plusieurs occurrences.
public static string CustomReplace(string srcText, string toFind, string toReplace, bool matchCase, bool replace0nce)
{
StringComparison sc = StringComparison.OrdinalIgnoreCase;
if (matchCase)
sc = StringComparison.Ordinal;
int pos;
while ((pos = srcText.IndexOf(toFind, sc)) > -1)
{
srcText = srcText.Remove(pos, toFind.Length);
srcText = srcText.Insert(pos, toReplace);
if (replace0nce)
break;
}
return srcText;
}
Cela peut ne pas être aussi efficace que certaines des autres réponses, mais j'aime bien la fonction CustomReplace écrite par sntbob.
Cependant, il y a un défaut. Si le remplacement de texte est récursif, cela provoquera une boucle infinie. Par exemple, CustomReplace ("je mange des bananes!", "Une", "banane", false, false) provoquerait une boucle infinie et la chaîne continuerait de grossir . Par exemple, après la 4ème itération, la chaîne be "je mange bbbbbananaanaanaanaanas!"
Si vous souhaitez uniquement remplacer les deux instances de "une" banane "à l'intérieur", vous devrez alors adopter une autre approche. J'ai modifié le code de sntbob pour tenir compte de ce cas. J'admets que c'est beaucoup plus compliqué, mais ça gère les remplacements récursifs.
public static string CustomReplace(string srcText, string toFind, string toReplace, bool matchCase, bool replaceOnce)
{
StringComparison sc = StringComparison.OrdinalIgnoreCase;
if (matchCase)
sc = StringComparison.Ordinal;
int pos;
int previousProcessedLength = 0;
string alreadyProcessedTxt = "";
string remainingToProcessTxt = srcText;
while ((pos = remainingToProcessTxt.IndexOf(toFind, sc)) > -1)
{
previousProcessedLength = alreadyProcessedTxt.Length;
//Append processed text up until the end of the found string and perform replacement
alreadyProcessedTxt += remainingToProcessTxt.Substring(0, pos + toFind.Length);
alreadyProcessedTxt = alreadyProcessedTxt.Remove(previousProcessedLength + pos, toFind.Length);
alreadyProcessedTxt = alreadyProcessedTxt.Insert(previousProcessedLength + pos, toReplace);
//Remove processed text from remaining
remainingToProcessTxt = remainingToProcessTxt.Substring(pos + toFind.Length);
if (replaceOnce)
break;
}
return alreadyProcessedTxt + remainingToProcessTxt;
}
Pourquoi ne pas simplement importer l'espace de noms Microsoft.VisualBasic et utiliser la méthode VB Strings.Replace?
https://msdn.Microsoft.com/en-us/library/Microsoft.visualbasic.strings.replace(v=vs.110).aspx
par exemple
var newString = Strings.Replace(SourceString, FindTextValue, ReplacementTextValue, 1, -1, Constants.vbTextCompare);
vbTextCompare force un remplacement insensible à la casse. Travail accompli.
D'accord, ce n'est pas du 'pur' C #, mais cela vous amène là où vous voulez aller avec beaucoup moins de complexité et de déconner.
Voici une autre alternative qui utilise StringComparison en tant que méthode d'extension. sur un objet StringBuilder. J'ai lu des articles indiquant qu'un StringBuilder pourrait être un peu plus efficace en mémoire que l'utilisation de chaînes. Vous pouvez facilement modifier cela pour travailler avec des chaînes si c'est ce dont vous avez besoin.
/// <summary>
/// Extension method to find/replace replaces text in a StringBuilder object
/// </summary>
/// <param name="original">Source StringBuilder object</param>
/// <param name="oldString">String to search for</param>
/// <param name="newString">String to replace each occurrance of oldString</param>
/// <param name="stringComparison">String comparison to use</param>
/// <returns>Original Stringbuilder with replacements made</returns>
public static StringBuilder Replace(this StringBuilder original,
string oldString, string newString, StringComparison stringComparison)
{
//If anything is null, or oldString is blank, exit with original value
if ( newString == null || original == null || string.IsNullOrEmpty(oldString))
return original;
//Convert to a string and get starting position using
//IndexOf which allows us to use StringComparison.
int pos = original.ToString().IndexOf(oldString, 0, stringComparison);
//Loop through until we find and replace all matches
while ( pos >= 0 )
{
//Remove the old string and insert the new one.
original.Remove(pos, oldString.Length).Insert(pos, newString);
//Get the next match starting 1 character after last replacement (to avoid a possible infinite loop)
pos = original.ToString().IndexOf(oldString, pos + newString.Length + 1, stringComparison);
}
return original;
}