String.Replace ignoring case

前端 未结 17 753
野趣味
野趣味 2020-11-29 19:03

I have a string called \"hello world\"

I need to replace the word \"world\" to \"csharp\"

for this I use:

string.Replace(\"World\", \"csharp\         


        
17条回答
  •  情深已故
    2020-11-29 19:50

    2.5X FASTER and MOST EFFECTIVE method than other's regular expressions methods:

    /// 
    /// Returns a new string in which all occurrences of a specified string in the current instance are replaced with another 
    /// specified string according the type of search to use for the specified string.
    /// 
    /// The string performing the replace method.
    /// The string to be replaced.
    /// The string replace all occurrences of . 
    /// If value is equal to null, than all occurrences of  will be removed from the .
    /// One of the enumeration values that specifies the rules for the search.
    /// A string that is equivalent to the current string except that all instances of  are replaced with . 
    /// If  is not found in the current instance, the method returns the current instance unchanged.
    [DebuggerStepThrough]
    public static string Replace(this string str,
        string oldValue, string @newValue,
        StringComparison comparisonType)
    {
    
        // Check inputs.
        if (str == null)
        {
            // Same as original .NET C# string.Replace behavior.
            throw new ArgumentNullException(nameof(str));
        }
        if (str.Length == 0)
        {
            // Same as original .NET C# string.Replace behavior.
            return str;
        }
        if (oldValue == null)
        {
            // Same as original .NET C# string.Replace behavior.
            throw new ArgumentNullException(nameof(oldValue));
        }
        if (oldValue.Length == 0)
        {
            // Same as original .NET C# string.Replace behavior.
            throw new ArgumentException("String cannot be of zero length.");
        }
    
    
        //if (oldValue.Equals(newValue, comparisonType))
        //{
        //This condition has no sense
        //It will prevent method from replacesing: "Example", "ExAmPlE", "EXAMPLE" to "example"
        //return str;
        //}
    
    
    
        // Prepare string builder for storing the processed string.
        // Note: StringBuilder has a better performance than String by 30-40%.
        StringBuilder resultStringBuilder = new StringBuilder(str.Length);
    
    
    
        // Analyze the replacement: replace or remove.
        bool isReplacementNullOrEmpty = string.IsNullOrEmpty(@newValue);
    
    
    
        // Replace all values.
        const int valueNotFound = -1;
        int foundAt;
        int startSearchFromIndex = 0;
        while ((foundAt = str.IndexOf(oldValue, startSearchFromIndex, comparisonType)) != valueNotFound)
        {
    
            // Append all characters until the found replacement.
            int @charsUntilReplacment = foundAt - startSearchFromIndex;
            bool isNothingToAppend = @charsUntilReplacment == 0;
            if (!isNothingToAppend)
            {
                resultStringBuilder.Append(str, startSearchFromIndex, @charsUntilReplacment);
            }
    
    
    
            // Process the replacement.
            if (!isReplacementNullOrEmpty)
            {
                resultStringBuilder.Append(@newValue);
            }
    
    
            // Prepare start index for the next search.
            // This needed to prevent infinite loop, otherwise method always start search 
            // from the start of the string. For example: if an oldValue == "EXAMPLE", newValue == "example"
            // and comparisonType == "any ignore case" will conquer to replacing:
            // "EXAMPLE" to "example" to "example" to "example" … infinite loop.
            startSearchFromIndex = foundAt + oldValue.Length;
            if (startSearchFromIndex == str.Length)
            {
                // It is end of the input string: no more space for the next search.
                // The input string ends with a value that has already been replaced. 
                // Therefore, the string builder with the result is complete and no further action is required.
                return resultStringBuilder.ToString();
            }
        }
    
    
        // Append the last part to the result.
        int @charsUntilStringEnd = str.Length - startSearchFromIndex;
        resultStringBuilder.Append(str, startSearchFromIndex, @charsUntilStringEnd);
    
    
        return resultStringBuilder.ToString();
    
    }
    

    Note: ignore case == StringComparison.OrdinalIgnoreCase as parameter for StringComparison comparisonType. It is the fastest, case-insensitive way to replace all values.


    Advantages of this method:

    • High CPU and MEMORY efficiency;
    • It is the fastest solution, 2.5 times faster than other's methods with regular expressions (proof in the end);
    • Suitable for removing parts from the input string (set newValue to null), optimized for this;
    • Same as original .NET C# string.Replace behavior, same exceptions;
    • Well commented, easy to understand;
    • Simpler – no regular expressions. Regular expressions are always slower because of their versatility (even compiled);
    • This method is well tested and there are no hidden flaws like infinite loop in other's solutions, even highly rated:

    @AsValeO: Not works with Regex language elements, so it's not universal method

    @Mike Stillion: There is a problem with this code. If the text in new is a superset of the text in old, this can produce an endless loop.


    Benchmark-proof: this solution is 2.59X times faster than regex from @Steve B., code:

    // Results:
    // 1/2. Regular expression solution: 4486 milliseconds
    // 2/2. Current solution: 1727 milliseconds — 2.59X times FASTER! than regex!
    
    // Notes: the test was started 5 times, the result is an average; release build.
    
    const int benchmarkIterations = 1000000;
    const string sourceString = "aaaaddsdsdsdsdsd";
    const string oldValue = "D";
    const string newValue = "Fod";
    long totalLenght = 0;
    
    Stopwatch regexStopwatch = Stopwatch.StartNew();
    string tempString1;
    for (int i = 0; i < benchmarkIterations; i++)
    {
        tempString1 = sourceString;
        tempString1 = ReplaceCaseInsensitive(tempString1, oldValue, newValue);
    
        totalLenght = totalLenght + tempString1.Length;
    }
    regexStopwatch.Stop();
    
    
    
    Stopwatch currentSolutionStopwatch = Stopwatch.StartNew();
    string tempString2;
    for (int i = 0; i < benchmarkIterations; i++)
    {
        tempString2 = sourceString;
        tempString2 = tempString2.Replace(oldValue, newValue,
            StringComparison.OrdinalIgnoreCase);
    
        totalLenght = totalLenght + tempString2.Length;
    }
    currentSolutionStopwatch.Stop();
    

    Original idea – @Darky711; thanks @MinerR for StringBuilder.

提交回复
热议问题