2011-03-05 3 views
0

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

Чтобы проиллюстрировать эту проблему:

string[] nested = { "mary;john;carl", "dog;cat;fish", "plainValue" } 
string list = string.Join(";", nested); 
string[] unnested = list.Split(';'); // EEK! returns 7 items, expected 3! 

Это будет производить список «Мария, Иоанна, CARL; собаки; кошки, рыбы, plainValue», значение я не могу разделить, чтобы получить три исходные вложенные строки из. Действительно, вместо трех исходных строк я бы получил 7 строк на split, и этот подход, таким образом, не работает вообще.

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

  • Как я могу позволить любые строковые значения быть упакованы/распакованы в списки?
    Я предпочитаю простые, простые решения по объему, если это возможно.

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

+0

Множество ответов касалось просто замены символа разделителя. Это не реально жизнеспособно, оно слишком простое и слишком хрупкое. Это не будет легко разрешать «любой» контент в списке, и он не будет обрабатывать глубокие вложенные списки, так как вам нужно будет определить множество специальных символов спереди. До сих пор кодировка Base64 была лучшим кандидатом, поскольку она удаляла использование символов разделителя для каждого элемента, кодируя значения. Я хотел бы посмотреть, может ли кто-нибудь придумать решение, используя escape-символы или подобное. В противном случае ответ Base64 будет принят в качестве рабочего решения. – Statement

ответ

1

Перед присоединением кодируйте свои строки с кодировкой base64.

+0

Это полезный ответ на мою проблему. +1. Однако Base64 действительно потребляет много места. Я еще не знаю, слишком ли велика дополнительная цена на потребление, но в противном случае это ответ кандидата. Вы поняли, что мне нужно кодировать значения, чтобы я мог безопасно разделить/присоединиться. Я думаю, что это также можно было бы сделать с экранированием персонажей, но я не могу обернуть голову вокруг этого метода. – Statement

+0

Я выбрал этот ответ, потому что реализация довольно тривиальна. Потенциальный недостаток, который я вижу, является неэффективным при работе с объемом памяти 1 МБ. @ [Niklas Karlsson] опубликовал другое решение, которое также, похоже, работает. Я еще не знаю, могут ли все символы использоваться на носителе данных (например, они хранятся в значениях реестра), но его подход, по-видимому, является наиболее эффективным с точки зрения памяти. Многие люди предлагают использовать другой разделительный характер, и этого может быть достаточно для случаев других людей. Мне нужны мои значения, чтобы содержать любые персонажи, поэтому мне не повезло с ними. – Statement

1

Ожидаемые товары: 7, потому что вы раскалываетесь с помощью char ;. Я хотел бы предложить, чтобы изменить код:

string[] nested = { "mary;john;carl", "dog;cat;fish", "plainValue" } 
string list = string.Join("@" nested); 
string[] unnested = list.Split('@'); // 3 strings again 
+0

Это не решит мою проблему, так как тогда я не смогу использовать @ в своих значениях. Я хочу, чтобы все разделители разделились. Кроме того, было бы больно создавать глубоко вложенные элементы. – Statement

0

Используйте другое значение, чем точка с запятой (;) для соединения. Например, вы можете использовать запятую (,), и вы получите "mary;john;carl,dog;cat;fish,plainValue". Когда вы снова разделите его на (,) в качестве разделителя, вы должны вернуть исходное значение строки.

+0

Это не решит мою проблему, так как тогда я не смогу использовать ее в своих значениях. Я хочу, чтобы все разделители разделились. Кроме того, было бы больно создавать глубоко вложенные элементы. – Statement

1

Рассматривали ли вы использование другого разделителя, например «|»?

Таким образом, объединенная строка будет «mary; john; carl | dog; cat; fish | plainValue» и когда вы вызываете list.split («|»); он будет возвращать три оригинальную струну

+0

Это не решит мою проблему, так как тогда я не смогу использовать | в моих ценностях. Я хочу, чтобы все разделители разделились. Кроме того, было бы больно создавать глубоко вложенные элементы. – Statement

2

попробовать:

const char joinChar = '╗'; // make char const 
string[] nested = { "mary;john;carl", "dog;cat;fish", "plainValue" }; 
string list = string.Join(Convert.ToString(joinChar), nested); 
string[] unnested = list.Split(joinChar); // eureka returns 3! 

с использованием символов ASCII за пределами нормального «набор» позволяет объединить и разделить, не разрушая вашу логику, которая отделена от ; полукокса.

+0

Это не решит мою проблему, так как тогда я не смогу использовать ╗ в своих значениях. Я хочу, чтобы все разделители разделились. Кроме того, было бы больно создавать глубоко вложенные элементы. – Statement

+0

Заявление, ╗ было примером символа вне нормального диапазона клавиатуры ascii. используйте любой символ, который вам нравится. я думаю, вам нужно будет сделать ваш вопрос более ясным, поскольку почти каждый ответ здесь интерпретирует ваше требование как это - вы жесткий руководитель задачи :-) –

+0

Я думаю, я мог бы быть яснее, но вопрос был указан * «Тогда эти элементы в turn может быть списком ** или другим значением, которое может содержать мой разделительный символ **. * *. – Statement

0

Я придумал свое решение.

Я могу кодировать длину элемента, а затем содержимое элемента. Он не будет использовать string.Split и string.Join вообще, но это решит мою проблему. Содержимое было бы не тронуто, и любой контент, который нуждается в кодировке, в свою очередь может использовать эту кодировку в своем пространстве содержимого.

Чтобы проиллюстрировать формат (константа заголовка длины):

< длиной содержимого> < сырого содержание>

Для иллюстрации формата (заголовок переменной длины):

< содержание l ength> < заголовок стоповый символ> < содержание сырого>

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

Пример 4 шестнадцатеричном (FFFF/65535 Максимальная длина):

0005Hello0005World

В последнем примере, мы можем уменьшить это:

5: Hello5: World

Тогда я мог бы найти первое событие : и сначала проанализировать длину, чтобы извлечь подстроку, которая следует за ней. После этого следующий элемент списка.

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

е: 5: Hello5: worldâ: 2: Hi4: Джон

  • (List - 14 charactes включая заголовки)
    • Hello (5 символов)
    • Мир (5 символов)
  • (список - 10 символов, включая заголовки)
    • Привет (2 символа)
    • Джон (4-х символов)

Недостаток состоит в том, что он явно требует длину всех элементов, даже если символ «shared separator» не присутствовал (это решение не использует разделители, если используется заголовок с фиксированной длиной).

0

Maby не так хорошо, как вы хотели. Но здесь идет :)

static void Main(string[] args) 
    { 
     string[] str = new string[] {"From;niklas;to;lasse", "another;day;at;work;", "Bobo;wants;candy"}; 
     string compiledString = GetAsString(str); 
     string[] backAgain = BackToStringArray(compiledString); 
    } 

    public static string GetAsString(string[] strings) 
    { 
     string returnString = string.Empty; 
     using (MemoryStream ms = new MemoryStream()) 
     { 
      using (BinaryWriter writer = new BinaryWriter(ms)) 
      { 
       writer.Write(strings.Length); 
       for (int i = 0; i < strings.Length; ++i) 
       { 
        writer.Write(strings[i]); 
       } 
      } 
      ms.Flush(); 

      byte[] array = ms.ToArray(); 
      returnString = Encoding.UTF8.GetString(array); 
     } 
     return returnString; 
    } 

    public static string[] BackToStringArray(string encodedString) 
    { 
     string[] returnStrings = new string[0]; 
     byte[] toBytes = Encoding.UTF8.GetBytes(encodedString); 
     using (MemoryStream stream = new MemoryStream(toBytes)) 
     { 
      using (BinaryReader reader = new BinaryReader(stream)) 
      { 
       int numStrings = reader.ReadInt32(); 
       returnStrings = new string[numStrings]; 
       for (int i = 0; i < numStrings; ++i) 
       { 
        returnStrings[i] = reader.ReadString(); 
       } 
      } 
     } 
     return returnStrings; 
    } 
+0

+1 (но мне нужно подождать еще 14 часов?). Он безопасно кодирует значения. Это похоже на эффективное решение для памяти, которое я опубликовал. Я действительно реализовал это, но использовал string.SubString и шестнадцатеричную нотацию длины, length.ToString («X4»). – Statement

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