Linq模式匹配

时间:2009-10-18 14:58:55

标签: c# linq pattern-matching

我正在使用正则表达式来匹配模式,请参阅以下示例中的示例我匹配字符串以计算元音。

void VowelsCountInEachWord()
{
  Regex rx = new Regex("[aeiou]");
  var words=new string[] 
                         {"aesthetic", "benevolent", "abstract",
                           "capricious", "complacent", "conciliatory",
                           "devious", "diligent", "discernible","dogmatic",
                           "eccentric","fallacious","indifferent","inquisitive",
                           "meticulous","pertinent","plausible", "reticent"
                         };

  var filter = from w in words where (rx.IsMatch(w.ToLower())) select new  

              {w,count=VowelsCounting(w)};


 foreach (var v in filter)
 {
     Console.WriteLine("String {0} contains {1} vowels", v.w, v.count);
 }

}

 public int VowelsCounting(string value)
 {

    int cnt=0;
    foreach (char c in value)
    {
         switch (c)
         {
              case 'a':cnt++;break;
              case 'e':cnt++;break;
              case 'i':cnt++;break;
              case 'o':cnt++;break;
              case 'u':cnt++;break;
           }
     }
            return cnt++;
  }

1)如果不使用正则表达式,C#是否提供匹配模式的任何构造?

2)对于字符串计算单个字符,我需要派生自己的方法吗?

4 个答案:

答案 0 :(得分:3)

你的解决方案并不坏,但如果你坚持:

var vowels = new char[] { 'a', 'e', 'i', 'o', 'u' };
var words = new string[] 
             {"aesthetic", "benevolent", "abstract",
               "capricious", "complacent", "conciliatory",
               "devious", "diligent", "discernible","dogmatic",
               "eccentric","fallacious","indifferent","inquisitive",
               "meticulous","pertinent","plausible", "reticent"
             };

var filter =
    (from w in words
    select new { w, count = w.ToLower().Count(c => vowels.Contains(c)) }).
        Where(item => item.count > 0);

编辑:正如有人在这里建议的那样,我删除了ToCharArray,我添加了ToLower check&也是一个零元音滤波器。

答案 1 :(得分:3)

  

1)不使用正则表达式   C#是否提供任何构造   匹配模式?

没有像正则表达式那样强大的功能,可以一次性为你提供一切。

  

2)计算个人角色   反对字符串我需要派生   我自己的方法?

我不推荐这种方法 ,但我只是为了表明您可以使用一些内置方法来实现它。你可以想象使用String.IndexOf并从0索引开始寻找“a”,并在循环中继续前进,同时在正匹配上递增计数器。然后重复“e”......“u”但它的效率远低于正则表达式或for循环。

更好的方法是通过char循环遍历字符串char,并将其提供给现有的switch语句或在某些集合中查找。

由于您想使用LINQ,以下是如何重写上述for循环理念以适应。请注意,这个想法类似于HuBeZa's solution所以+1那里。但是,我使用列表进行查找并使用StringComparison.InvariantCultureIgnoreCase枚举来忽略大小写:

var vowels = new List<string> { "a", "e", "i", "o", "u" };
var query = words.Select(s => new
            {
                Text = s,
                Count = s.Count(c => vowels.Exists(vowel => 
                    vowel.Equals(c.ToString(), 
                        StringComparison.InvariantCultureIgnoreCase)))
            });
foreach (var item in query)
{
    Console.WriteLine("String {0} contains {1} vowels", item.Text, item.Count);
}

我原来的正则表达式响应如下。


正则表达式方法

有一个比你正在使用的更好的正则表达式解决方案。我不确定你是否意识到这一点,所以我认为这是一个帖子。在问题#1中,你说“不使用正则表达式”,但恕我直言,问题是你问你是否必须推导出自己的方法。问题#2

您可以使用返回的MatchCollection上的Regex.Matches methodCount property来缩短代码:

Regex rx = new Regex("[aeiou]");
// to ignore case use: new Regex("[aeiou]", RegexOptions.IgnoreCase);
string[] words =
{
    "aesthetic", "benevolent", "abstract",
    "capricious", "complacent", "conciliatory",
    "devious", "diligent", "discernible","dogmatic",
    "eccentric","fallacious","indifferent","inquisitive",
    "meticulous","pertinent","plausible", "reticent"
};

foreach (string input in words)
{
    Console.WriteLine("String {0} contains {1} vowels",
        input, rx.Matches(input).Count);
}

// if you really want to use LINQ
var query = from s in words
            select new
            {
                Text = s,
                Count = rx.Matches(s).Count
            };
foreach (var item in query)
{
    Console.WriteLine("String {0} contains {1} vowels", item.Text, item.Count);
}

顺便说一句,您可以通过更改2项来进一步缩短原始代码:

1)字符串数组声明(我在上面的例子中完成了这个)
2)让你的案例陈述落到下一个案例标签:

switch (c)
{
    case 'a':
    case 'e':
    case 'i':
    case 'o':
    case 'u':
        cnt++;
        break;
}
使用LINQ查询更新

编辑。它与OP的差别不大,只是使用匹配方法。

答案 2 :(得分:2)

以下解决方案仅包含项目,如果它包含元音,并且它将是最快的解决方案。

var filter = from w2 in
                 (from w in words
                  select new
                  {
                      w,
                      count =
                          w.ToLower().ToCharArray().Count(
                            c => c == 'a' || 
                                c == 'e' || 
                                c == 'i' || 
                                c == 'o' || 
                                c == 'u')
                  })
             where (w2.count > 0)
             select w2; 

答案 3 :(得分:1)

每个人都让这太复杂了:

Regex rx = new Regex("[aeiou]", RegexOptions.IgnoreCase);

var query = from w in words
            let vowelCount = rx.Matches(w).Count
            where vowelCount != 0
            select new { w, vowelCount };

当然如果你不需要一个有元音的单词列表(什么单词没有?)而你想要做的就是输出计数,那么就更容易使用一个循环。