webentwicklung-frage-antwort-db.com.de

So ignorieren Sie den Fall in String.replace

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";

Wie man "Kamel" im Satz durch "Pferd" trotz string.Replace ersetzt, unterstützt ignoreCase auf der linken Zeichenfolge nicht?

37
Xaqron

Verwenden Sie einen regulären Ausdruck:

var regex = new Regex( "camel", RegexOptions.IgnoreCase );
var newSentence = regex.Replace( sentence, "horse" );

Natürlich passt dies auch zu Wörtern, die Kamel enthalten, aber es ist nicht klar, ob Sie das wollen oder nicht.

Wenn Sie genaue Übereinstimmungen benötigen, können Sie einen benutzerdefinierten MatchEvaluator verwenden.

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 );
    }
} 

Wird im vorherigen Beispiel verwendet, um die Übereinstimmung in einem Bereich wie folgt zu umschließen:

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 ) );
}
51
tvanfosson

Fügen Sie eine Erweiterungsmethode für string hinzu, um den Trick auszuführen:

Verwendungszweck:

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;
    }
}
17
Tom Beech

Hier ist eine Erweiterungsmethode, die einen StringComparison verwendet, wobei string.IndexOf verwendet wird:

    [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();
    }

Übrigens, hier ist auch eine ähnliche Contains-Methode, die auch einen StringComparison benötigt:

    [Pure]
    public static bool Contains(this string source, string value, StringComparison comparisonType)
    {
        return source.IndexOf(value, comparisonType) >= 0;
    }

Einige 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));
    }
}
12
johv

Hier ist meine Erweiterungsmethode, die Tom Beechs kombiniert, mit der Rekursivität von sntbobs und einem saubereren Fix für den Fehler, auf den ksun hingewiesen hat.

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;
}

Verwendungszweck:

string source = "banana";
Console.WriteLine(source.Replace("AN", "banana", StringComparison.OrdinalIgnoreCase));

Ergebnis:

bbananabananaa

Und wenn Sie möchten, dass der rekursive Charakter optional ist:

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;
}

Verwendungszweck:

string source = "banana";
Console.WriteLine(source.Replace("AN", "banana", StringComparison.OrdinalIgnoreCase, false));

Ergebnis:

bbananaana

6
Johnie Karr

Nutzen Sie StringComparison wegen seiner praktischen 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)
    }

Sicher wäre Nice, wenn die C # String-Klasse eine ignoreCase()-Methode wie Java hätte.

3
whiteshooz

Sie können auch String.IndexOf verwenden 

http://msdn.Microsoft.com/de-de/library/system.string.indexof.aspx

Auf diese Weise erhalten Sie möglicherweise eine etwas bessere Leistung als mit RegExpressions (ich hasse sie, weil sie nicht intuitiv und leicht zu vermasseln sind, obwohl dieser einfache .Net-Funktionsaufruf das eigentliche chaotische RegEx abstrahiert und nicht viel Platz bietet Fehler), aber das ist wahrscheinlich kein Problem für Sie; Computer sind heutzutage wirklich schnell, oder? :) Die Überladung für IndexOf, die ein StringComparison-Objekt benötigt, ermöglicht es Ihnen, optional die Groß-/Kleinschreibung zu ignorieren. Da IndexOf das erste Vorkommen an einer angegebenen Position zurückgibt, müssen Sie eine Schleife codieren, um einen String mit mehreren Vorkommen zu verarbeiten.

2
Quanta
    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;
    }
1
sntbob

Es ist vielleicht nicht so effizient wie andere Antworten, aber ich mag die CustomReplace-Funktion, die von sntbob geschrieben wurde.

Es ist jedoch ein Fehler darin. Wenn die Ersetzung des Textes rekursiv ist, führt dies zu einer Endlosschleife. Zum Beispiel würde CustomReplace ("Ich esse Bananen!", "Eine", "Banane", False, False) eine Endlosschleife verursachen, und die Zeichenfolge würde immer größer werden Zum Beispiel würde die Zeichenfolge nach der vierten Iteration größer werden sei "ich esse bbbbbananaanaanaanaanas!"

Wenn Sie nur die zwei Instanzen einer "inneren" Banane ersetzen möchten, müssen Sie einen anderen Ansatz wählen. Ich habe den Code von sntbob geändert, um diesen Fall zu berücksichtigen. Ich gebe zu, dass es viel komplizierter ist, aber es handelt sich um rekursive Ersetzungen.

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;
    }
1
ksun

Warum nicht einfach den Microsoft.VisualBasic-Namespace importieren und die Methode VB Strings.Replace verwenden?

https://msdn.Microsoft.com/en-us/library/Microsoft.visualbasic.strings.replace(v=vs.110).aspx

z.B 

var newString = Strings.Replace(SourceString, FindTextValue, ReplacementTextValue, 1, -1, Constants.vbTextCompare);

vbTextCompare erzwingt einen Ersatz, bei dem die Groß- und Kleinschreibung nicht berücksichtigt wird. Job erledigt. 

Okay, es ist kein "reines" C #, aber es bringt Sie dahin, wo Sie mit viel weniger Komplexität und Durcheinander herumkommen möchten.

0
Neil Haughton

Hier ist eine weitere Alternative, die StringComparison als Erweiterungsmethode verwendet. in einem StringBuilder-Objekt. Ich habe einige Artikel gelesen, die darauf hinweisen, dass ein StringBuilder mit Speicher etwas effizienter ist als die Verwendung von Zeichenfolgen. Sie können dies leicht ändern, um mit Strings zu arbeiten, wenn Sie das brauchen.

/// <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;
    }
0
J.J. Willis