将List <string>编码为plain String并将其解码回来的最简单方法是什么?</string>

时间:2009-05-12 15:47:17

标签: c# serialization

我想我已经遇到过这个要求十几次了。但我永远找不到令人满意的解决方案。例如,有一个字符串集合,我想通过一个只允许普通字符串的通道序列化(到磁盘或通过网络)。 我几乎总是最终使用“分裂”和“加入”与荒谬的分隔符,如

  

“::: == - == :::”。

像这样:

public static string encode(System.Collections.Generic.List<string> data)
{
    return string.Join(" :::==--==::: ", data.ToArray());
}
public static string[] decode(string encoded)
{
    return encoded.Split(new string[] { " :::==--==::: " }, StringSplitOptions.None);
}

但这个简单的解决方案显然存在一些缺陷。该字符串不能包含分隔符字符串。因此,编码的字符串不能再重新编码。

AFAIK,全面的解决方案应该包括在编码时转义分隔符并在解码时转义。虽然问题听起来很简单,但我相信完整的解决方案可能会占用大量代码。我想知道是否有任何技巧可以让我构建编码器和放大器解码器只有几行代码?

12 个答案:

答案 0 :(得分:5)

您可以在List&lt;&gt;上使用.ToArray属性然后序列化数组 - 然后可以将其转储到磁盘或网络,并在另一端使用反序列化重新构建。

代码不多,您可以使用已在.net框架中测试和编码的序列化技术。

答案 1 :(得分:5)

向System.Web添加引用和using,然后:

public static string Encode(IEnumerable<string> strings)
{
    return string.Join("&", strings.Select(s => HttpUtility.UrlEncode(s)).ToArray());
}

public static IEnumerable<string> Decode(string list)
{
    return list.Split('&').Select(s => HttpUtility.UrlDecode(s));
}

大多数语言都有一对使用Url“百分比”编码的实用程序函数,这非常适合在这种情况下重复使用。

答案 2 :(得分:4)

您可能希望查看CSV文件的格式化方式。

  • 转义deliminater的所有实例,例如“在字符串中
  • 将“item”
  • 列表中的每个项目换行
  • 使用简单的分隔符
  • 加入

我不相信这个问题有解决方案。

答案 3 :(得分:3)

这是一种可能适合的老派技术 -

通过将每个字符串[]的宽度存储为每行中的固定宽度前缀来进行序列化。

所以

 string[0]="abc"
 string[1]="defg"
 string[2]=" :::==--==::: "

变为

0003abc0004defg0014 :::==--==::: 

...前缀的大小足以满足字符串最大长度

答案 4 :(得分:2)

您可以使用XmlDocument来处理序列化。这将为您处理编码。

public static string encode(System.Collections.Generic.List<string> data)
{
    var xml = new XmlDocument();
    xml.AppendChild(xml.CreateElement("data"));
    foreach (var item in data)
    {
        var xmlItem = (XmlElement)xml.DocumentElement.AppendChild(xml.CreateElement("item"));
        xmlItem.InnerText = item;
    }
    return xml.OuterXml;
}

public static string[] decode(string encoded)
{
    var items = new System.Collections.Generic.List<string>();
    var xml = new XmlDocument();
    xml.LoadXml(encoded);
    foreach (XmlElement xmlItem in xml.SelectNodes("/data/item"))
        items.Add(xmlItem.InnerText);
    return items.ToArray();
}

答案 5 :(得分:2)

我只是在每个字符串前面加上它的长度和一个终结符来表示长度的结束。

abc
defg
hijk
xyz
546
4.X

变为

3: abc 4: defg 4: hijk 3: xyz 3: 546 3: 4.X

完全没有限制或限制,非常简单。

答案 6 :(得分:2)

Json.NET是一种非常简单的方法来序列化您可以想象的任何对象。 JSON保持紧凑,并且比XML更快。

List<string> foo = new List<string>() { "1", "2" };
string output = JsonConvert.SerializeObject(foo);
List<string> fooToo = (List<string>)JsonConvert.DeserializeObject(output, typeof(List<string>));

答案 7 :(得分:1)

您不需要手动执行此操作。正如其他答案所指出的那样,有很多方法可以内置或以其他方式序列化/反序列化。

但是,如果您决定自己完成这项工作,则不需要 多少代码:

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.Length = 0;
        }
        else
        {
            sb.Append(c);
            escaped = false;
        }
    }

    yield return sb.ToString();
}

答案 8 :(得分:1)

如果您愿意使用长度为2个字符的分隔符,则可以更简单地完成:

在java代码中:

StringBuilder builder = new StringBuilder();

for(String s : list) {
  if(!s.isEmpty()) {
    builder.append("||");
  }
  builder.append(s.replace("|", "|p"));
}

然后回来:

for(String item : encodedList.split("||")) {
  list.add(item.replace("|p", "|"));
}

答案 9 :(得分:0)

为什么不使用Xstream来序列化它,而不是重新发明自己的序列化格式?

非常简单:

new XStream().toXML(yourobject)

答案 10 :(得分:0)

在您的文件中加入 System.Linq 库,并将您的功能更改为:

    public static string encode(System.Collections.Generic.List<string> data, out string delimiter)
    {
        delimiter = ":";
        while(data.Contains(delimiter)) delimiter += ":";
        return string.Join(delimiter, data.ToArray());
    }
    public static string[] decode(string encoded, string delimiter)
    {
        return encoded.Split(new string[] { delimiter }, StringSplitOptions.None);
    }

答案 11 :(得分:0)

有很多文本标记语言,任何功能

考虑到输入的简单性,很多人都会琐碎地运作,这取决于如何:

  1. 人类可读,你想要编码
  2. 对api更改有弹性,应该是
  3. 解析它是多么容易
  4. 为它编写或获取解析器是多么容易。
  5. 如果最后一个是最重要的,那么只需使用现有的xml库MS供应:

    class TrivialStringEncoder
    {
        private readonly XmlSerializer ser = new XmlSerializer(typeof(string[]));
    
        public string Encode(IEnumerable<string> input)
        {
            using (var s = new StringWriter())
            {
                ser.Serialize(s, input.ToArray());
                return s.ToString();
            }       
        }
    
        public IEnumerable<string> Decode(string input)
        {
            using (var s = new StringReader(input))
            {
                return (string[])ser.Deserialize(s);            
            }       
        }
    
        public static void Main(string[] args)
        {
            var encoded = Encode(args);
            Console.WriteLine(encoded);
            var decoded = Decode(encoded);
            foreach(var x in decoded)
                Console.WriteLine(x);
        }
    }
    

    在输入“A”,“&lt;”,“&gt;”上运行你得到(编辑格式):

    <?xml version="1.0" encoding="utf-16"?>
    <ArrayOfString 
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
        xmlns:xsd="http://www.w3.org/2001/XMLSchema">
      <string>A</string>
      <string>&lt;</string>
      <string>&gt;</string>
    </ArrayOfString>
    A
    <
    >
    

    详细,缓慢,但非常简单,不需要额外的库