Что является более уникальным разделителем, чем запятая для разделения строк? - PullRequest
23 голосов
/ 03 мая 2009

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

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

Я использую C #, если это имеет значение.

Ответы [ 21 ]

27 голосов
/ 03 мая 2009

| будет следующим в моем списке и часто используется в качестве альтернативы CSV. Google "труба с разделителями", и вы найдете много примеров.

string[] items = new string[] {"Uno","Dos","Tres"};

string toEncrypt = String.Join("|", items);

items = toEncrypt.Split(new char[] {'|'}, StringSplitOptions.RemoveEmptyEntries);

foreach(string s in items)
  Console.WriteLine(s);

И поскольку всем нравится критиковать кодировку и не предоставлять код, вот один из способов кодирования текста, чтобы ваша | delim не будет сталкиваться.

string[] items = new string[] {"Uno","Dos","Tres"};

for (int i = 0; i < items.Length; i++)
    items[i] = Convert.ToBase64String(Encoding.UTF8.GetBytes(items[i]));

string toEncrypt = String.Join("|", items);

items = toEncrypt.Split(new char[] {'|'}, StringSplitOptions.RemoveEmptyEntries);

foreach (string s in items)
     Console.WriteLine(Encoding.UTF8.GetString(Convert.FromBase64String(s)));
15 голосов
/ 03 мая 2009

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

У вас есть два основных варианта, если вы хотите сделать его водонепроницаемым:

1: используйте символ, который невозможно ввести, например символ '\ 0':

Регистрация:

string combined = string.Join("\0", inputArray);

Split:

string[] result = combined.Split('\0');

2: экранировать строку и использовать экранированный символ в качестве разделителя, например, URL, кодирующий значения, и использовать & в качестве разделителя:

Регистрация:

string combined = string.Join("&", inputArray.Select<string,string>(System.Web.HttpUtility.UrlEncode).ToArray());

Split:

string[] result = combined.Split('&').Select<string,string>(System.Web.HttpUtility.UrlDecode).ToArray();
8 голосов
/ 03 мая 2009

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

Сохраните их в список или строку [] и сериализуйте / десериализуйте их. Используйте XML, если вы хотите удобочитаемость человеком, или взаимодействуйте - или двоично сериализуйте их, если вы этого не делаете. Вы можете легко зашифровать вывод в любом случае, при этом нет никакой двусмысленности или создать свои собственные экранирующие процедуры.

В C # это меньше LOC и требует меньше времени для написания, чем этот ответ. Нет никакого оправдания тому, чтобы накатить собственное решение.

7 голосов
/ 03 мая 2009

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

Вспомните обратные слэзы + двойные кавычки внутри строк в двойных кавычках.

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

3 голосов
/ 03 мая 2009

Будет ли пользователь вводить строки с разделителями в текстовые поля или они будут вводить отдельные строки, которые затем будут встроены в строки с разделителями вашим кодом?

В первом случае может быть лучше переосмыслить ваш интерфейс. Например, пользователь может вводить одну строку за раз в текстовое поле и нажимать кнопку «Добавить в список» после каждого.

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

EDIT

Поскольку в нескольких комментариях к другим ответам запрашивается код, вот метод для создания строки, разделенной запятыми, с использованием обратной косой черты в качестве escape-символа:

public static string CreateDelimitedString(IEnumerable<string> items)
{
    StringBuilder sb = new StringBuilder();

    foreach (string item in items)
    {
        sb.Append(item.Replace("\\", "\\\\").Replace(",", "\\,"));
        sb.Append(",");
    }

    return (sb.Length > 0) ? sb.ToString(0, sb.Length - 1) : string.Empty;
}

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

public static IEnumerable<string> GetItemsFromDelimitedString(string s)
{
    bool escaped = false;
    StringBuilder sb = new StringBuilder();

    foreach (char c in s)
    {
        if ((c == '\\') && !escaped)
        {
            escaped = true;
        }
        else if ((c == ',') && !escaped)
        {
            yield return sb.ToString();
            sb.Remove(0, sb.Length);
        }
        else
        {
            sb.Append(c);
            escaped = false;
        }
    }

    yield return sb.ToString();
}

А вот пример использования:

string[] test =
    {
        "no commas or backslashes",
        "just one, comma",
        @"a comma, and a\ backslash",
        @"lots, of\ commas,\ and\, backslashes",
        @"even\\ more,, commas\\ and,, backslashes"
    };

    string delimited = CreateDelimitedString(test);
    Console.WriteLine(delimited);

    foreach (string item in GetItemsFromDelimitedString(delimited))
    {
        Console.WriteLine(item);
    }
3 голосов
/ 03 мая 2009

Любой из нестандартных символов pipe |, backtick `, tilde ~, bang! Или точка с запятой; вероятно, будет работать. Однако, если вы пойдете по этому пути, вы на действительно рискуете отказаться от юзабилити. Попросить их оставить запятые с обратной косой чертой или что-то еще, умоляя пропустить одну.

Если CSV невозможен, вам следует изменить свой пользовательский интерфейс. (Черт, в любом случае вам следует держаться подальше от CSV для пользовательского ввода!) Вы говорите «текстовое поле», поэтому я предполагаю, что вы находитесь в Интернете или в какой-то форме выигрышных форм или WPF (определенно не в консоли). Все это дает вам лучший контроль над пользовательским интерфейсом, чем одно текстовое поле, и заставляет пользователей соответствовать вашему сложному дизайну пользовательского интерфейса.

Больше информации определенно поможет лучше направлять ответы.

Однако, в качестве примера экранирования запятой с обратной косой чертой. Обратите внимание, что вы не можете избежать обратной косой черты перед запятой с этим. Так что @ "uno, dos, tr \\, es" в конечном итоге будет {"uno", "dos", "tr \ es"}.

string data = @"uno, dos, tr\,es";
string[] items = data.Split(','); // {"uno", " dos", @"tr\", "es"}
List<string> realitems = new List<string>();
for (int i=items.Length-1; i >= 0; i--)
{
    string item = items[i];
    if (item.Length == 0) { realitems.Insert(0, ""); continue; }

    if (realitems.Count == 0) { realitems.Insert(0, item); }
    else
    {
        if (item[item.Length - 1] == '\\') { realitems[0] = item + "," + realitems[0]; }
        else { realitems.Insert(0, item); }
    }
}

// Should end up with {"uno", " dos", "tr,es"}
2 голосов
/ 03 мая 2009

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

Вместо одного символа, возможно, попробуйте строку, которая будет достаточно случайной, чтобы никто ее не использовал. Что-то вроде "#! @! #".

1 голос
/ 03 мая 2009

Определите символ, который не используется, а затем используйте его. Ваша последняя объединенная строка может начинаться с символа, который должен быть с этой точки и использоваться в качестве разделителя.

пример: ваши пользователи вводят "брюки",;,;,;,;,; " и "| ~~ |" Вы перебираете набор символов, пока не найдете тот, который не используется. Может быть, скажем, "$" Ваша последняя объединенная строка - это "$ants $,;,;,;,;,; $ | ~~ |" Начальный символ сообщает вашей программе, какой символ должен использоваться в качестве разделителя. Таким образом, нет запрещенных символов, точка.

1 голос
/ 03 мая 2009

Марк Брэкетт имеет правильный ответ. Я только добавлю, что само количество ответов на этот простой вопрос должно вообще помешать вам использовать строки с разделителями. Пусть это будет «словом к мудрым».

1 голос
/ 03 мая 2009

Как уже отмечалось, любой выбранный вами персонаж имеет шанс появиться на входе, поэтому вам придется обрабатывать экранирование. XML может быть хорошим форматом для сериализации, так как я считаю, что .NET имеет хорошую поддержку создания и удаления XML. Это, вероятно, будет гораздо более надежным, чем попытка реализовать экранирование вашего персонажа, а также будет более расширяемым в будущем.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...