Есть ли нечувствительная к регистру строка, заменяемая в .Net без использования Regex?
Недавно мне пришлось выполнить некоторые замены строк в .net и обнаружил, что я разрабатываю функцию замены регулярных выражений для этой цели. Получив его на работу, я не мог не думать о том, что в .Net не существует встроенной в регистр нечувствительной операции замены.
Конечно, когда существует так много других строковых операций, которые поддерживают нечувствительность к регистру, например:
var compareStrings = String.Compare("a", "b", blIgnoreCase);
var equalStrings = String.Equals("a", "b", StringComparison.CurrentCultureIgnoreCase);
то для замены должен быть встроенный эквивалент?
Ответы
Ответ 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
Не должно быть слишком сложно создать собственное расширение.