2016-04-08 3 views
0

У меня есть строка текста и хочу, чтобы она содержала не более одного единственного экземпляра определенного символа (,). Поэтому я хочу сохранить первый, но просто удалите все последующие вхождения этого символа.Как удалить все, кроме первых вхождения символа из строки?

Как я могу сделать это самым элегантным способом с помощью C#?

ответ

2

Вы можете использовать счетчик переменной и StringBuilder эффективно создавать новую строку:

var sb = new StringBuilder(text.Length); 
int maxCount = 1; 
int currentCount = 0; 
char specialChar = ','; 
foreach(char c in text) 
    if(c != specialChar || ++currentCount <= maxCount) 
     sb.Append(c); 
text = sb.ToString(); 

Этот подход не является кратчайшим, но это эффективно и вы можете указать символ-счетчик, чтобы сохранить.

Вот более «элегантный» путь с помощью LINQ:

int commasFound = 0; int maxCommas = 1; 
text = new string(text.Where(c => c != ',' || ++commasFound <= maxCommas).ToArray()); 

мне не нравится, потому что она требует, чтобы изменить переменную из запроса, так что это вызывает побочный эффект.

+0

Я назвал бы LINQ один довольно элегантный :) – Rawling

+1

@Rawling: отредактировал мой ответ на комментарий, почему я не люблю его (даже если я люблю LINQ). –

+0

Мне очень нравится ваш оператор LINQ, но я не понимаю побочных эффектов, которые вы упомянули еще. Что вы ожидаете там? –

3

Это работает, но не самый элегантный наверняка :-)

string a = "12,34,56,789"; 
int pos = 1 + a.IndexOf(','); 
return a.Substring(0, pos) + a.Substring(pos).Replace(",", string.Empty); 
+0

Я нахожу его изящным;) Имеет только один недостаток, если вы хотите сохранить 2 символа f.e. –

0

Вы могли бы написать функцию, как следующий один, что бы разделить строку на две секции по месту нахождения того, что вы искали (с помощью метода String.Split()) для и это будет только удалить совпадения из второй секции (с использованием String.Replace()):

public static string RemoveAllButFirst(string s, string stuffToRemove) 
{ 
    // Check if the stuff to replace exists and if not, return the original string 
    var locationOfStuff = s.IndexOf(stuffToRemove); 
    if (locationOfStuff < 0) 
    { 
     return s; 
    } 
    // Calculate where to pull the first string from and then replace the rest of the string 
    var splitLocation = locationOfStuff + stuffToRemove.Length; 
    return s.Substring(0, splitLocation) + (s.Substring(splitLocation)).Replace(stuffToRemove,""); 
} 

Вы могли бы просто назвать его с помощью:

var output = RemoveAllButFirst(input,","); 

красивее подход действительно может включать создание метод расширения, который обрабатывается это немного более чисто:

public static class StringExtensions 
{ 
    public static string RemoveAllButFirst(this string s, string stuffToRemove) 
    { 
      // Check if the stuff to replace exists and if not, return the 
      // original string 
      var locationOfStuff = s.IndexOf(stuffToRemove); 
      if (locationOfStuff < 0) 
      { 
       return s; 
      } 
      // Calculate where to pull the first string from and then replace the rest of the string 
      var splitLocation = locationOfStuff + stuffToRemove.Length; 
      return s.Substring(0, splitLocation) + (s.Substring(splitLocation)).Replace(stuffToRemove,""); 
    } 
} 

, который будет вызываться через:

var output = input.RemoveAllButFirst(","); 

Вы можете see a working example of it here.

+0

'StringExtensions' должен быть статическим классом, а первый параметр должен быть' этой строкой s' – Itsik

+0

По какой-то причине похоже, что мой ответ был отправлен в середине ответа, не заметив меня. Я обновил функцию соответственно. Спасибо за головы. –

1

Регулярные выражения элегантны, верно?

Regex.Replace("Eats, shoots, and leaves.", @"(?<=,.*),", ""); 

Это заменяет каждую запятую, если перед ней есть запятая, без ничего.

(На самом деле, это, вероятно, не элегантно - это может быть только одна строка кода, но она также может быть O(n^2) ...)

+0

, когда я помещаю это в тестер, он не работает. Квантификатор внутри lookbehind делает его нефиксированной шириной – user1040975

+0

@ user1040975 Возможно, вы используете другой аромат регулярного выражения. – Rawling

1

Если вы не иметь дело с большими строками и вам reaaaaaaly как Linq oneliners :

public static string KeepFirstOccurence (this string @string, char @char) 
{ 
    var index = @string.IndexOf(@char); 
    return String.Concat(String.Concat(@string.TakeWhile(x => @string.IndexOf(x) < index + 1)), String.Concat(@string.SkipWhile(x=>@string.IndexOf(x) < index)).Replace(@char.ToString(), "")); 
} 
0
static string KeepFirstOccurance(this string str, char c) 
    { 
     int charposition = str.IndexOf(c); 
     return str.Substring(0, charposition + 1) + 
        str.Substring(charposition, str.Length - charposition) 
        .Replace(c, ' ').Trim(); 
    } 
-1

Довольно короткая с Linq; разделить строку на символы, сохранить отдельный набор и присоединиться к строке.

text = string.Join("", text.Select(c => c).Distinct()); 
Смежные вопросы