Шаблоны для работы со строками (в C # или других языках) - PullRequest
1 голос
/ 10 сентября 2009

Я часто пишу довольно некрасивый код, когда выполняю строковые манипуляции. Код выполняет то, что ожидалось, но я хотел бы чувствовать себя удовлетворенным тем, как он выглядит так же, как и работает. Существуют ли хорошие книги, сайты, форумы, посвященные распространенным проблемам манипуляции со строками? А как бы вы кодировали следующие примеры сценариев?

Простой сценарий: у меня есть коллекция объектов, для которых я хочу объединить результат определенного метода для каждого объекта и отделить каждую строку с помощью «И».

Этот код помог бы, но он не дает того теплого уютного ощущения, которое вы получите после написания какого-то красивого кода ...;).

List<MyClass> myColl = ..... // initialize the collection..
StringBuilder sb = new StringBuilder();
bool isFirst = true;
foreach (MyClass obj in myColl) {
    if (!isFirst) {
        sb.Append(" AND ");
    }
    isFirst = false;
    sb.Append(obj.MyStringBuildingMethod());
}

Возможно, было бы лучше, если бы я использовал лямбда-выражения:

List<MyClass> myColl = ..... // initialize the collection..
string result = String.Join(" AND ", myColl.Select(i => i.MyStringBuildingMethod()).ToArray());

А теперь более сложный сценарий: я хочу разбить строку на разделителе, а затем разбить каждую часть на ключ / значение. Значение заключено в одинарные кавычки, и если разделитель находится внутри значения, мы не должны делиться на него. Следующий код делает то, что должен, но кажется, что я использовал клейкую ленту или что-то в этом роде;;)

string csvString = "name='Andersson, Per',country='Sweden',city='Stockholm'";
Dictionary<string, string> keyValues = new Dictionary<string, string>();

bool isInsideQuote = false;
int lastPosition = 0;
for (int i = 0; i < csvString.Length; i++) {
    if (csvString[i] == ',' && !isInsideQuote) {
        string[] keyValuePair = csvString.Substring(lastPosition, i - lastPosition).Split("=".ToCharArray(), 2);
        if (keyValuePair.Length == 2) {
            keyValues.Add(keyValuePair[0], keyValuePair[1].TrimStart("'".ToCharArray()).TrimEnd("'".ToCharArray()));
        }
        lastPosition = i + 1;
    }

    if (csvString[i] == '\'') {
        isInsideQuote = !isInsideQuote;
    }
}

string[] lastKeyValuePair = csvString.Substring(lastPosition).Split("=".ToCharArray(), 2);
if (lastKeyValuePair.Length == 2) {
    keyValues.Add(lastKeyValuePair[0], lastKeyValuePair[1].TrimStart("'".ToCharArray()).TrimEnd("'".ToCharArray()));
}

Ответы [ 3 ]

4 голосов
/ 10 сентября 2009

Вы можете использовать метод String.Join(string delimiter, string[] words). В синтаксисе C # 3.0 это может выглядеть следующим образом:

var words = new string[] 
                      {
                         "this",
                         "that",
                         "the other"
                      };

var concatenatedResult = String.Join(" and ", words);

//should output "this and that and the other"
Console.WriteLine(concatenatedResult);

Если у вас есть общий список и вы хотите объединить его значения, вы можете сделать следующее:

var words = new List<object>()
                    {
                      5,
                      DateTime.Now,
                      "something else"
                    };

var concatenatedResult = String.Join(" and ", words.Select(i => i.ToString()).ToArray());
//should output "5 and [system time] and something else"
Console.WriteLine(concatenatedResult);

Console.ReadLine();

Обратите внимание, что второй пример был извлечен из другого сообщения StackOverflow: Преобразовать список (объекта) в список (строки) .

Я посмотрел на IL для метода Join, и он должен быть достаточно сопоставимым по скорости, если не быстрее, чем использование класса StringBuilder. Я хотел убедиться, что экземпляры класса String не были объединены в коде, что было бы очень медленно по сравнению с подходом, показанным в OP.

2 голосов
/ 10 сентября 2009

Я бы добавил А для каждой записи, а затем просто удалил последний И в конце ...

List<MyClass> myColl = ..... // initialize the collection..
StringBuilder sb = new StringBuilder();
foreach (MyClass obj in myColl)   
    sb.Append(obj.MyStringBuildingMethod() + " AND ");
string s = sb.ToString(0, sb.Length - 5);
0 голосов
/ 10 сентября 2009

Я полагаю, что это немного менее запутанно, чем у вашего второго примера, хотя это зависит от того, что строка довольно строго отформатирована. Разбор строк не всегда хорош.

string csvString = "name='Andersson, Per',country='Sweden',city='Stockholm'";

csvString = csvString.Replace("',", "'|");
string[] parts = csvString.Split('|');
foreach (string s in parts)  {
  string[] moreParts = s.Split('=');

  string key = moreParts[0];
  string value = moreParts[1].Trim("'"); 
  // do stuff?
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...