1

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

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

4 回答 4

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 检查和零元音过滤器。

于 2009-10-18T15:11:45.647 回答
3

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

没有什么比正则表达式更强大的了,它可以一次性为您提供一切。

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

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

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

由于您想使用 LINQ,以下是如何重写上述 for 循环的想法以适应。请注意,这个想法类似于HuBeZa 的解决方案,所以在那里 +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直接冲突,您询问是否必须派生自己的方法。

您可以使用Regex.Matches 方法和返回的 MatchCollection 的Count 属性来缩短代码:

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) 让你的 case 语句落入下一个 case 标签:

switch (c)
{
    case 'a':
    case 'e':
    case 'i':
    case 'o':
    case 'u':
        cnt++;
        break;
}

编辑:用 LINQ 查询更新。它与 OP 所拥有的没什么不同,只是使用 Matches 方法。

于 2009-10-18T15:56:55.087 回答
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; 
于 2009-10-18T15:27:00.633 回答
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 };

当然,如果您不需要包含元音的单词列表(哪些单词没有?)并且您只想输出计数,那么使用循环会更容易。

于 2009-10-18T16:16:39.393 回答