2015-10-07 2 views
1

Я хочу заменить отдельные вхождения символа, но не два в строке с использованием C#.Заменить один символ, но не два в строке

Например, я хочу заменить & пустой строкой, но не тогда, когда ocurrence равен &&. Другим примером, a&b&&c стал бы ab&&c после замены.

Если я использую регулярное выражение, например &[^&], оно также будет соответствовать символу после &, и я не хочу его заменять.

Другое решение, которое я нашел, это перебрать символы строки.

Знаете ли вы, что такое более чистое решение?

+1

Как насчет '&&&' или '&&&&', следует ли их заменить? – PetSerAl

+0

Я думаю, что это не настоящий сценарий для моей проблемы, но в этом случае только подстрока с нечетным числом «&» будет заменена на все «&», кроме последнего «&». «&&&» будет «&&» и «&&&&» будет «&&&&» – dhalfageme

ответ

5

Вы можете соответствовать как & и && (или любое число повторений) и только заменить одного, с пустая строка:

str = Regex.Replace(str, "&+", m => m.Value.Length == 1 ? "" : m.Value); 
+0

Мне понравился стиль. Его комбинация регулярных выражений и 'C#' особенность :-) –

+3

Это на самом деле усложнение того, что необходимо. Результат может быть достигнут простым регулярным выражением без добавления LINQ. Мне также нравится LINQ, но здесь он абсолютно избыточный. –

+2

@stribizhev LINQ использует лямбда-выражения, но лямбда-выражения не LINQ. – PetSerAl

1

Вы можете использовать это регулярное выражение: @"(?<!&)&(?!&)"

var str = Regex.Replace("a&b&&c", @"(?<!&)&(?!&)", ""); 
Console.WriteLine(str); // ab&&c 
2

Чтобы соответствовать только один & (не предшествуют или следуют &), используйте просмотровых обходные(?<!&) и (?!&):

(?<!&)&(?!&) 

См regex demo

Вы пытались использовать отрицательный класс символов, который все равно соответствует персонажу, и вам нужно использовать внешний вид/look-behind, чтобы просто проверить отсутствие/присутствие персонажа, не потребляя его.

См regular-expressions.info:

Отрицательный опережения незаменим, если вы хотите, чтобы соответствовать что-то не следует что-то другое. При объяснении character classes в этом руководстве объясняется, почему вы не можете использовать отрицательный класс символов для соответствия q, за которым следует u. Отрицательный взгляд обеспечивает решение: q(?!u).

Lookbehind имеет тот же эффект, но работает в обратном направлении. Он сообщает движку регулярного выражения временно отступить назад в строке, чтобы проверить, можно ли совместить текст внутри lookbehind. (?<!a)b соответствует "b", которому не предшествует "a", используя отрицательный lookbehind. Он не соответствует cab, но соответствует b (и только b) в постелях или долгах.

+0

Очень хорошо объяснили и задокументировали. Проголосовали, спасибо – dhalfageme

0

Вы можете пойти с этим:

public static string replacement(string oldString, char charToRemove) 
{ 
    string newString = ""; 
    bool found = false; 
    foreach (char c in oldString) 
    { 
     if (c == charToRemove && !found) 
     { 
      found = true; 
      continue; 
     } 
     newString += c; 
    } 
    return newString; 
} 

Который, как родовое как можно

0

Я бы использовал что-то вроде этого, которое ИМО должно быть лучше, чем при использовании Regex:

public static class StringExtensions 
{ 
    public static string ReplaceFirst(this string source, char oldChar, char newChar) 
    { 
     if (string.IsNullOrEmpty(source)) return source; 
     int index = source.IndexOf(oldChar); 
     if (index < 0) return source; 
     var chars = source.ToCharArray(); 
     chars[index] = newChar; 
     return new string(chars); 
    } 
} 
0

я внести свой вклад в это заявление от комментариев:

в этом случае, только подстрока с нечетным числом «&» будут заменены все "&" кроме последнего "&". «& & &» будет «& &» и «& & & &» будет «& & & &»

Это довольно изящное решение с использованием balancing groups (хотя я бы не назвал это особенно чистым и легко читать).

Код:

string str = "11&222&&333&&&44444&&&&55&&&&&"; 
str = Regex.Replace(str, "&((?:(?<2>&)(?<-2>&)?)*)", "$1$2"); 

Выход:

11222&&333&&44444&&&&55&&&& 

ideone demo


  1. Он всегда совпадает с первым & (не снят).
  2. Если за ним следует четное число &, они сопоставляются и сохраняются в $1. Вторая группа захватывается первой из пары, но затем она вычитается вторым.
  3. Однако, если есть нечетное число из &, необязательная группа (?<-2>&)? не соответствует, и группа не вычитается. Затем $2 захватит дополнительную &

Например, соответствие предмета "&&&&", первый символ потребляется и не захватывается(). Второй и третий символы сопоставлены, но $2 вычитается(). Для последнего символа фиксируется $2().Последние 3 символа были сохранены в $1, и есть & в $2.
Затем замена "$1$2" == "&&&&".

+0

Я действительно не читал, что это должно было быть «более чистым решением», когда я впервые разместил это. – Mariano

Смежные вопросы