Подтвердить что ты не робот

Есть ли нечувствительная к регистру строка, заменяемая в .Net без использования Regex?

Недавно мне пришлось выполнить некоторые замены строк в .net и обнаружил, что я разрабатываю функцию замены регулярных выражений для этой цели. Получив его на работу, я не мог не думать о том, что в .Net не существует встроенной в регистр нечувствительной операции замены.

Конечно, когда существует так много других строковых операций, которые поддерживают нечувствительность к регистру, например:

var compareStrings  = String.Compare("a", "b", blIgnoreCase);
var equalStrings    = String.Equals("a", "b", StringComparison.CurrentCultureIgnoreCase);

то для замены должен быть встроенный эквивалент?

4b9b3361

Ответ 1

Нашел один в комментариях здесь: http://www.codeproject.com/Messages/1835929/this-one-is-even-faster-and-more-f flex-modified.aspx

static public string Replace(string original, string pattern, string replacement, StringComparison comparisonType)
{
     return Replace(original, pattern, replacement, comparisonType, -1);
}

static public string Replace(string original, string pattern, string replacement, StringComparison comparisonType, int stringBuilderInitialSize)
{
     if (original == null)
     {
         return null;
     }

     if (String.IsNullOrEmpty(pattern))
     {
         return original;
     }


     int posCurrent = 0;
     int lenPattern = pattern.Length;
     int idxNext = original.IndexOf(pattern, comparisonType);
     StringBuilder result = new StringBuilder(stringBuilderInitialSize < 0 ? Math.Min(4096, original.Length) : stringBuilderInitialSize);

     while (idxNext >= 0)
     {
        result.Append(original, posCurrent, idxNext - posCurrent);
        result.Append(replacement);

        posCurrent = idxNext + lenPattern;

        idxNext = original.IndexOf(pattern, posCurrent, comparisonType);
      }

      result.Append(original, posCurrent, original.Length - posCurrent);

      return result.ToString();
}

Должно быть самым быстрым, но я не проверял.

В противном случае вы должны сделать то, что предложил Саймон, и использовать функцию замены VisualBasic. Это то, что я часто делаю из-за его нечувствительных к регистру возможностей.

string s = "SoftWare";
s = Microsoft.VisualBasic.Strings.Replace(s, "software", "hardware", 1, -1, Constants.vbTextCompare);

Вы должны добавить ссылку на dll Microsoft.VisualBasic.

Ответ 2

Это не идеально, но вы можете импортировать Microsoft.VisualBasic и использовать Strings.Replace для этого. В противном случае я думаю, что это случай, когда вы катитесь самостоятельно или придерживаетесь регулярных выражений.

Ответ 3

Здесь используется метод расширения. Не знаю, где я его нашел.

public static class StringExtensions
{
    public static string Replace(this string originalString, string oldValue, string newValue, StringComparison comparisonType)
    {
        int startIndex = 0;
        while (true)
        {
            startIndex = originalString.IndexOf(oldValue, startIndex, comparisonType);
            if (startIndex == -1)
                break;

            originalString = originalString.Substring(0, startIndex) + newValue + originalString.Substring(startIndex + oldValue.Length);

            startIndex += newValue.Length;
        }

        return originalString;
    }

}

Ответ 4

Это адаптация VB.NET ответа rboarman выше с необходимыми проверками на нулевые и пустые строки, чтобы избежать бесконечного цикла.

Public Function Replace(ByVal originalString As String, 
                        ByVal oldValue As String, 
                        ByVal newValue As String, 
                        ByVal comparisonType As StringComparison) As String
    If Not String.IsNullOrEmpty(originalString) AndAlso 
       Not String.IsNullOrEmpty(oldValue) AndAlso 
       newValue IsNot Nothing Then
        Dim startIndex As Int32

        Do While True
            startIndex = originalString.IndexOf(oldValue, startIndex, comparisonType)
            If startIndex = -1 Then Exit Do
            originalString = originalString.Substring(0, startIndex) & newValue & 
                             originalString.Substring(startIndex + oldValue.Length)
            startIndex += newValue.Length
        Loop
    End If

    Return originalString
End Function

Ответ 5

Мои 2 цента:

public static string Replace(this string originalString, string oldValue, string newValue, StringComparison comparisonType)
{
    if (originalString == null)
        return null;
    if (oldValue == null)
        throw new ArgumentNullException("oldValue");
    if (oldValue == string.Empty)
        return originalString;
    if (newValue == null)
        throw new ArgumentNullException("newValue");

    const int indexNotFound = -1;
    int startIndex = 0, index = 0;
    while ((index = originalString.IndexOf(oldValue, startIndex, comparisonType)) != indexNotFound)
    {
        originalString = originalString.Substring(0, index) + newValue + originalString.Substring(index + oldValue.Length);
        startIndex = index + newValue.Length;
    }

    return originalString;
}



Replace("FOOBAR", "O", "za", StringComparison.OrdinalIgnoreCase);
// "FzazaBAR"

Replace("", "O", "za", StringComparison.OrdinalIgnoreCase);
// ""

Replace("FOO", "BAR", "", StringComparison.OrdinalIgnoreCase);
// "FOO"

Replace("FOO", "F", "", StringComparison.OrdinalIgnoreCase);
// "OO"

Replace("FOO", "", "BAR", StringComparison.OrdinalIgnoreCase);
// "FOO"

Ответ 6

Обновление в .NET Core 2. 0+ (август 2017 г.)

Это изначально доступно в .NET Core 2.0 + с String.Replace который имеет следующие перегрузки

public string Replace (string oldValue, string newValue, StringComparison comparisonType);
public string Replace (string oldValue, string newValue, bool ignoreCase, System.Globalization.CultureInfo culture);

PS: Вы можете просмотреть исходный код .NET Core, если хотите увидеть, как MS его реализовала.

Так что вы можете использовать любой из этих:

"A".Replace("a", "b", StringComparison.CurrentCultureIgnoreCase);
"A".Replace("a", "b", true, CultureInfo.CurrentCulture);

Legacy.NET Framework 4.8 - опция для проектов VB

Visual Basic имеет параметр Option Compare параметров, который может быть установлен в Binary или Text

При установке значения " Text все сравнения строк в вашем проекте по умолчанию не чувствительны к регистру.

Так что, как предлагали другие ответы, если вы CompareMethod Microsoft.VisualBasic.dll, при вызове Strings.Replace если вы явно не передаете метод CompareMethod метод на самом деле откладывается до опции Compare для вашего файла или проекта, используя [OptionCompare] Параметр Атрибут

Так что любое из следующего также будет работать (верхний вариант доступен только в VB, но оба зависят от VisualBasic.dll)

Option Compare Text

Replace("A","a","b")
Replace("A","a","b", Compare := CompareMethod.Text)

Ответ 7

Вы можете использовать Microsoft.VisualBasic.Strings. Replace Microsoft.VisualBasic.Strings. Replace и передайте в Microsoft.VisualBasic.CompareMethod. Text Microsoft.VisualBasic.CompareMethod. Text для замены без учета регистра:

Dim myString As String = "One Two Three"
myString = Replace(myString, "two", "TWO", Compare:= CompareMethod.Text)

Ответ 8

Я знаю, что в структуре нет консервированного экземпляра, но здесь есть другая версия метода расширения с минимальным количеством утверждений (хотя, возможно, и не самая быстрая), для удовольствия. Другие версии функций замены размещены на http://www.codeproject.com/KB/string/fastestcscaseinsstringrep.aspx и Есть ли альтернатива строке. Замените, что не зависит от регистра? ".

public static string ReplaceIgnoreCase(this string alterableString, string oldValue, string newValue){
    if(alterableString == null) return null;
    for(
        int i = alterableString.IndexOf(oldValue, System.StringComparison.CurrentCultureIgnoreCase);
        i > -1;
        i = alterableString.IndexOf(oldValue, i+newValue.Length, System.StringComparison.CurrentCultureIgnoreCase)
    ) alterableString =
        alterableString.Substring(0, i)
        +newValue
        +alterableString.Substring(i+oldValue.Length)
    ;
    return alterableString;
}

Ответ 9

Ну, встроенный String.Replace просто не поддерживает поиск без учета регистра. Он документировал:

Этот метод выполняет порядковый номер (с учетом регистра и нечувствительность к культуре) поиск, чтобы найти OldValue.

http://msdn.microsoft.com/en-us/library/fk49wtc1.aspx

Не должно быть слишком сложно создать собственное расширение.