2014-07-09 46 views
0

输入 - 字符串:"TAG1xxxTAG2yyyTAG3zzzTAG1tttTAG1bbb"最好的方法解析字符串到词典术语

预期的结果:对TAG1 = {xxx,,ttt,bbb}, TAG2 = {yyy}, TAG3 = {zzz}.

我做到了使用正则表达式,但我真的用Regex.Replace和不糊涂使用返回值。我想改进这个代码,那么它是如何实现的呢?

using System; 
using System.Collections.Generic; 
using System.Text.RegularExpressions; 

namespace TermsTest 
{ 
    class Program 
    { 
     static void Main(string[] args) 
     { 
      string[] tags = { "TAG1", "TAG2", "TAG3", "TAG4", "TAG5", "TAG6", "TAG7", "TAG8" }; 
      string file = "TAG2jjfjfjndbfdjTAG1qqqqqqqTAG3uytygh fhdjdfTAG5hgjdhfghTAG6trgfmxc hdfhdTAG2jfksksdhjskTAG3kdjbjvbsjTAG2jskjdjdvjvbxjkvbjdTAG2jkxcndjcjbkjn"; 

      string tag = "(" + string.Join("|", tags) + ")"; 

      var dictionary = new Dictionary<string, List<string>>(tags.Length); 
      Regex.Replace(file, string.Format(@"({0})(.+?)(?={0}|$)", tag), match => 
                      { 
                       string key = match.Groups[1].Value, value = match.Groups[3].Value; 
                       if (dictionary.ContainsKey(key)) 
                        dictionary[key].Add(value); 
                       else 
                        dictionary[key] = new List<string> {value}; 
                       return ""; 
                      }); 
      foreach (var pair in dictionary) 
      { 
       Console.Write(pair.Key + " =\t"); 
       foreach (var entry in pair.Value) 
       { 
        Console.Write(entry + " "); 
       } 
       Console.WriteLine(); 
       Console.WriteLine(); 
      } 
     } 
    } 
} 

回答

3
string input = "TAG1xxxTAG2yyyTAG3zzzTAG1tttTAG1bbb"; 
var lookup = Regex.Matches(input, @"(TAG\d)(.+?)(?=TAG|$)") 
        .Cast<Match>() 
        .ToLookup(m => m.Groups[1].Value, m => m.Groups[2].Value); 

foreach (var kv in lookup) 
{ 
    Console.WriteLine(kv.Key + " => " + String.Join(", ", kv)); 
} 

OUTPUT:

TAG1 => xxx, ttt, bbb 
TAG2 => yyy 
TAG3 => zzz 
+0

谢谢,看起来好多了! –

0

这是.NET CaptureCollection对象一个唯一的.NET功能,让你重复使用相同的拍摄组多次完美的工作。

使用此正则表达式,并使用Matches创建MatchCollection:

(?:TAG1(.*?(?=TAG|$)))?(?:TAG2(.*?(?=TAG|$)))?(?:TAG3(.*?(?=TAG|$)))? 

然后检查捕获:

  • Groups[1].Captures将包含所有的TAG1
  • Groups[2].Captures将包含所有TAG2
  • Groups[3].Captures将包含所有的TAG3

从那里,它是你的最终数据结构的一小步。

为了减少潜在的回溯,可以使令牌原子:

(?>(?:TAG1(.*?(?=TAG|$)))?)(?>(?:TAG2(.*?(?=TAG|$)))?)(?>(?:TAG3(.*?(?=TAG|$)))?) 

有关如何工作的,见Capture Groups that can be Quantified细节。

+0

这似乎是很慢的,为前,100个标签。或者我错了? –

+0

好吧,让我们通过将组原子化来减少回溯的可能性:'(?>(?: TAG1(。*?(?= TAG | $)))?)(?>(?: TAG2(。*?( (?= TAG | $)))?)(?>(?: TAG3(。*?(?= TAG | $)))?)' – zx81

0

什么是你想要做的就是简单的分组相同的标签值的,所以应该更容易使用GroupBy方法:

string input = "TAG1xxxTAG2yyyTAG3zzzTAG1tttTAG1bbb"; 
var list = Regex.Matches(input, @"(TAG\d+)(.+?)(?=TAG\d+|$)") 
       .Cast<Match>() 
       .GroupBy(m => m.Groups[1].Value, 
         (key, values) => string.Format("{0} = {{{1}}}", 
              key, 
              string.Join(", ", 
               values.Select(v => v.Groups[2])))); 
var output = string.Join(", ", list); 

这产生作为output字符串"TAG1 = {xxx, ttt, bbb}, TAG2 = {yyy}, TAG3 = {zzz}"

0

我n请确保我知道你在这个问题上的所有假设和惯例;但是这给了我同样的结果:

var tagColl = string.Join("|", tags); 
var tagGroup = string.Format("(?<tag>{0})(?<val>[a-z]*)", tagColl); 

var result = from x in Regex.Matches(file, tagGroup).Cast<Match>() 
       where x.Success 
       let pair = new { fst = x.Groups["tag"].Value, snd = x.Groups["val"].Value } 
       group pair by pair.fst into g 
       select g; 

和一个简单的测试是:

Console.WriteLine(string.Join("\r\n", from g in result 
             let coll = string.Join(", ", from item in g select item.snd) 
             select string.Format("{0}: {{{1}}}", g.Key, coll)));