Как безопасно разделить строки? - PullRequest
4 голосов
/ 18 октября 2010

Когда мы хотим разделить жало по каким-либо причинам, мы (по крайней мере, я) стараемся разделить, используя символ (pipe) |, так как очень редко можно найти кого-то или что приложение использует его настрока ... но что произойдет, если она использует?

Ну, будет просто брошено Crash :)

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

String.Format(
         "{1}{0}{2}{0}{3}{0}{4}",
         (char)2,
         myFirstString,
         mySecondString,
         myThirdString,
         myFourthString);

и когда мы хотим извлечь строку отверстия в ее части

String.Split((char)2);

Isэто сейф ? Должен ли я принять этот способ безопасного разделения строки? Есть ли другая техника безопасности?

Ответы [ 6 ]

8 голосов
/ 18 октября 2010

Может быть «безопаснее», чем канал, потому что он реже, но оба способа неоптимальны, потому что ограничивают вас подмножеством возможных строк.

Подумайте об использовании правильной кодировки - такой, которая однозначно кодирует список произвольных строк. Самым простым с точки зрения кодирования, вероятно, является просто сериализация string[]. Вы можете использовать BinaryFormatter или XmlSerializer или что-то еще.

Если результат имеет в виде строки, и он должен быть short , тогда вы можете попробовать что-то вроде этого:

  • Кодировка: (список строк в одну строку)
    • Заменить каждый ! на !e и каждый | на !p в каждой строке. Теперь ни одна из строк не содержит |, и вы можете легко изменить это.
    • Объединить строки, используя | в качестве разделителя.
  • Декодирование: (одна строка вернуться к списку строк)
    • Разделить на символ |.
    • Заменить все !p на | и !e на ! в каждой строке. Это восстанавливает оригинальные строки.
3 голосов
/ 18 октября 2010

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

Возможно, вы захотите подумать, нужно ли сначала объединять несколько строк в одну гигантскую строку.Если причина их существования заключается исключительно в представлении «разделенных» текстовых данных в вашего приложения, вы можете создать данные в виде последовательности строк (например, string[]) с самого начала.В этом случае «разбора» не потребуется.

Если, с другой стороны, данные должны быть сохранены и использованы позднее, есть несколько вариантов.Например:

  1. База данных : сохранить каждую строку как строку в таблице базы данных.Разделение не требуется.
  2. Назначенный разделитель : Хранить строки в плоском файле со специальным разделителем, который обозначает конец текущей строки.Очевидно, этот символ должен быть таким, чтобы он не мог быть частью допустимой подстроки.Например, если ваши строки не могут содержать символ конвейера, как вы говорите, то это разумный выбор для разделителя.
  3. Escape-последовательности : Например, * является разделителем,** обозначает звездочку в строке.Это будет означать, что ни один символ не зарезервирован для использования в качестве стража (что делает его непредставимым).С другой стороны, разбор становится нетривиальной задачей.
  4. Целевой формат : например, XML.Если вы считаете, что для этого необходимо «экранировать» определенные символы, это, по сути, является расширением пункта 3, но теперь проблема относится к вашим библиотекам XML.
2 голосов
/ 18 октября 2010

Я думаю, что использование непечатаемых символов скорее неясно, чем безопасно.Если вы хотите безопасности, решением будет сериализация / десериализация вашего List<string>.

2 голосов
/ 18 октября 2010

Было бы лучше, если бы вы могли помочь, никогда не объединять строки вместе.Подобное расщепление - это запах кода.

Конечно, использование управляющего символа «более вероятно» не будет иметь проблем, но все равно не идеально.Если вам действительно нужно это сделать, используйте NUL (\0).Этот персонаж, по крайней мере, имеет историю сторожевого стража.

1 голос
/ 18 октября 2010

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

a,b,"c,d"

производит:

new[] { "a", "b", "c,d" }

Это может помочь http://www.codeproject.com/KB/database/CsvReader.aspx

0 голосов
/ 18 октября 2010

Зависит от ожидаемого содержимого строки.Если ожидаемые строки могут иметь непечатаемые символы, то, возможно, нет.Другой способ - избавиться от строк, которые вы собираетесь разделить, это выглядит как дополнительная работа, но может быть помещено в многоразовый помощник:

var string1 = "string|1";
var string2 = "string |2";
var string3 = "string| 3";
var string4 = "string | 4";

var stringToSplit = MergeStrings(string1, string2, string3, string4);

var results = SplitString( stringToSplit );

foreach(string result in results)
{
    Trace.WriteLine( result );
}

, который использует следующие методы.

public string MergeStrings(params string[] strings)
{
    var stringBuilder = new StringBuilder();

    foreach(var s in strings)
    {
        stringBuilder.Append( s.Replace( "|", "||" ) );
        stringBuilder.Append( " | " );
    }

    return stringBuilder.ToString();
}

public IEnumerable<string> SplitString(string stringToSplit)
{
    var results = stringToSplit.Split( new[] { " | " }, StringSplitOptions.RemoveEmptyEntries );

    return results.Select( result => result.Replace( "||", "|" ) );
}

Возможно, вы захотите сделать символ разделителя настраиваемым.

...