2013-05-10 65 views
0

我有一个扩展的一个问题已经问here查找字符串C#字符的最发生,返回最长的复现字符的字符串

但是我想回到最长的一组名单重新确定原始字符串中的字符,而不是它们相对计数的字符列表,按照最高排序。

我相当精通的联系,但从来没有翻过来在字符串中查询字符类型的实例,并认为有人可以给我一个提示,以帮助我理解LINQ的具体使用情况...

感谢

+0

ie。为“abbbbccd”返回“bbbb” – matthewbaskey 2013-05-10 22:15:57

+0

你能否提供一个例子。更好地理解这个问题会有所帮助。 – arunlalam 2013-05-10 22:26:49

+1

如果输入是“abbbbccdb” - 你希望输出是“bbbb”还是“bbbbb”? – dugas 2013-05-10 23:00:01

回答

4

我假设你想要的最长的串。例如,对于aabccc你想要

我还假设问题域是Unicode字符的字符串。不幸的是,.NET的System.String是一组代码单元。要统计或索引Unicode字符,您必须将它们作为代码点处理。最简单的方法是将编码更改为UTF-32,因为每个编码点有一个int,而编码点是Unicode字符的数字标识符[一般而言]。

之后,要找到相同字符的最长子序列,您必须遍历整个序列。运行长度编码是我用作中间步骤的一种通用方法。在找到最长的子序列的代码点和长度后,我重新创建它们的一串。

 const string test = "aabccc"; // contains barber pole characters 
     Console.WriteLine(test); 

     var longest = test.ToCodepoints().RunLengthEncode().OrderByDescending(itemCount => itemCount.Item2).First(); 
     var subsequence = String.Concat(Enumerable.Repeat(Char.ConvertFromUtf32(longest.Item1), longest.Item2)); 
     Console.WriteLine(subsequence); 

将字符串转换为代码点相当于转换为UTF-32。它可以用System.Text.Encoding方法完成,但最终会产生一个字节数组,然后必须将其转换为码点。这里是一个IEnumerable,它产生一个int的序列。

public static IEnumerable<int> ToCodepoints(this String s) 
    { 
     var codeunits = s.ToCharArray(); 
     var i = 0; 

     while (i < codeunits.Length) 
     { 
      int codepoint; 
      if (Char.IsSurrogate(codeunits[i])) 
      { 
       codepoint = Char.ConvertToUtf32(codeunits[i], codeunits[i + 1]); 
       i += 2; 
      } 
      else 
      { 
       codepoint = codeunits[i]; 
       i += 1; 
      } 
      yield return codepoint; 
     } 

    } 

运行长度编码产生的码点的一个元组(Item1)和相同码点的每个子序列中运行(Item2)的长度:

public static IEnumerable<Tuple<T, int>> RunLengthEncode<T>(this IEnumerable<T> sequence) 
    { 
     T item = default(T); // value never used 
     int length = 0; 
     foreach (var nextItem in sequence) 
     { 
      if (length == 0) // first item 
      { 
       item = nextItem; 
       length = 1; 
      } 
      else if (item.Equals(nextItem)) // continuing run 
      { 
       length++; 
      } 
      else // run boundary 
      { 
       var run = Tuple.Create(item, length); 
       item = nextItem; 
       length = 1; 
       yield return run; 
      } 
     } 
     if (length > 0) // last run 
     { 
      yield return Tuple.Create(item, length); 
     } 
+0

你能解释一下'理发师极人物'的意思吗,谷歌搜索引发你在理发店外看到的螺旋柱。我假设你可能指的是管道字符||,但是将第一部分代码粘贴到控制台应用程序中会带来带有问号的小方块。请澄清。谢谢。我会继续你的榜样。 – matthewbaskey 2013-05-11 09:37:22

+0

Unicode Character'[BARBER POLE](http://www.fileformat.info/info/unicode/char/1f488/index.htm)'(U + 1F488)仅仅是一个由两个System .Char元素。请参阅(绝对最低限度每个软件开发人员绝对,肯定必须知道Unicode和字符集)[http://www.joelonsoftware.com/articles/Unicode.html] Joel Spolsky。 (IE)上的Visual Studio和StackOverflow应该显示该字符正常。其他浏览器/系统/字体可能会回落到包含十六进制数字的框中。但cmd.exe认为它是两个字符,它不知道,所以它显示? – 2013-05-11 10:47:59

+0

好的谢谢你,除了它返回了一个404,因为你的方括号,所以更新的链接是http://www.joelonsoftware.com/articles/Unicode.html你的例子已经为我打开了很多新的领土。我确实找到了有关CHARGEN服务的维基百科http://en.wikipedia.org/wiki/Barber_pole#Computer_science的参考资料。我会错过使用默认的UTF16编码,因为它也使用代码点?我看到很多语言在Utf32 – matthewbaskey 2013-05-11 14:14:36

4

使用链接的例子:

var largest = input.GroupBy(x => x).OrderByDescending(x => x.Count()).First(); 
var asString = new string(largest.Key, largest.Count()); 
+0

感谢这是干净,快速和简洁。作为一名Web开发人员,而不是系统程序员,对我来说,使用简单易用的语法会更有帮助,因为我必须跟踪大量客户端技术和样式问题。我明白我现在在哪里绊倒,实际上我有第一个陈述,但不知道如何在第二个陈述中得到结果并将其输入到一个新的字符串中。 – matthewbaskey 2013-05-11 09:43:08

+0

我应该指定一个更具体的例子,我希望有一个很好的简短表达式来做到这一点 – matthewbaskey 2013-05-11 15:51:11

+0

请注意,@magister想要最长的循环字符串,例如“aabbbaa” - >“bbb”不是“aaaa”。 – 2013-05-12 22:10:01

2

没有必要创建大量的中间物体。您只需要跟踪最长序列中的字符和该序列的长度:

char longest = '\0'; 
int longestLength = 0; 

char last = '\0'; 
int lastLength = 0; 

foreach (char c in input) 
{ 
    if (c == last) 
    { 
     lastLength++; 

     if (lastLength > longestLength) 
     { 
      longestLength = lastLength; 
      longest = c; 
     } 
    } 
    else 
    { 
     lastLength = 1; 
    } 

    last = c; 
} 

var result = new string(longest, longestLength); 
+0

此方法不考虑字符编码。试试这个:string input =“aabccc”; //包含理发极点字符 – 2014-08-05 11:06:36

+1

@XavierDecoster对于最多16位的Unicode字符,此方法工作正常。例如'string input =“aab \ u2764 \ u2764 \ u22605”;'是aab❤❤❤★并且正确地导致了❤❤❤。然而,[barber极点字符](http://www.fileformat.info/info/unicode/char/1f488/index.htm)高于16位字符的阈值,因此需要代理字符对来编码它。你可以调整这种方法在每个阶段最多存储两个字符,并使用['Char.IsSurrogate'](http://msdn.microsoft.com/en-us/library/96xe6etk(v = vs.110))。 aspx)来检测替代品。 – 2014-08-05 13:47:38

相关问题