2012-04-29 171 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