2012-04-29 139 views
2

我有以下两个字符串。重复字符串压缩

uncompressed "(A(2),I(10),A,A,A,A(3),R,R,R,R,A,A)" 
compressed "(A(2),I(10),3A,A(3),4R,2A)" 

忽略格式的任何条目(n)或I(n)的,你可以看到,当我们发现任何连续重复字符它会被替换在该位置和计数的单个条目。

我知道必须有一个优雅的方式来做到这一点,但我不断想出丑陋的看起来嵌套循环。

字符串中的数据来自ISO8211文件格式,并标识要应用于子字段中数据的格式。

我相信这可能是与LINQ的一行来完成,但我的想法(今晚)

+0

请有关语言标签添加到您的问题。 –

+0

自从你说LINQ以来,我认为它是C#(VB.NET?)? – Ryan

回答

2

的技术称为Run Length Encoding

下面是使用Python的例子:

from itertools import groupby 
uncompressed = "(A(2),I(10),A,A,A,A(3),R,R,R,R,A,A)" 
counted = [(k, len(list(g))) for k, g in groupby(uncompressed.split(','))] 
compressed = ','.join(k if cnt==1 else str(cnt)+k for k, cnt in counted) 
+0

非常好,对于我的所有搜索结果,我似乎都无法正确地确定问题,以至于得不到一丝线索。运行长度编码在ISO8211规范中未提及,天才。谢谢您的帮助。 – blackmob

1

好了,不完全是一个单行。这将做到这一点:

string str = "(A(2),I(10),A,A,A,A(3),R,R,R,R,A,A)"; 

string prev = null; 
int cnt = 0; 
string result = 
    "(" + String.Join(",", 
    (str.TrimStart('(').TrimEnd(')') + ",").Split(',').Select(x => { 
    if (x == prev) { 
     cnt++; 
     return null; 
    } else { 
     string temp = cnt > 1 ? cnt.ToString() + prev : prev; 
     prev = x; 
     cnt = 1; 
     return temp; 
    } 
    }).Where(x => x != null) 
) + ")"; 
+0

感谢您的建议,这与我目前的解决方案非常相似。我已经标记了Raymond Hettinger的答案,因为它命名了编码方法。谢谢你的帮助。 – blackmob

0

下面是做到这一点的方法,使用LINQ的GroupBy

static string RLE(string s) { 
    s = s.Substring(1, s.Length - 2); 

    char? l = null; 
    int i = 0; 

    return "(" + string.Join(",", s.Split(',').GroupBy(c => { 
     if(c.Length != 1) { 
      i++; 
      return i++; 
     } 

     if(c[0] == l) { 
      return i; 
     } 

     l = c[0]; 
     return ++i; 
    }).Select(x => (x.Count() > 1 ? x.Count().ToString() : string.Empty) + x.First())) + ")"; 
} 
+0

感谢您的帮助。 Regards Ben – blackmob