2009-10-18 4 views
1

Я использую регулярное выражение для сопоставления шаблонов, например, пример в следующем примере. Я сопоставляю строку для подсчета гласных.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) Для подсчета индивидуального символа в строке требуется ли мне собственный метод?

+0

Надеюсь, вы получили свой ответ. Добавьте к этому тегу 'regex'. – HuBeZa

ответ

3

1) Без использования регулярных выражений делает C# предлагают любую конструкцию для соответствием шаблона?

Ничего такого мощного, как регулярное выражение, которое дает вам все за один выстрел.

2) Для подсчета индивидуального характера против строки мне нужно сделать, чтобы получить мой собственный метод?

Я не рекомендую этот подход, но я о том, что просто, чтобы показать, что вы могли бы использовать некоторые встроенные в методе ее достижения. Вы могли бы использовать String.IndexOf и искать «а», начиная с индекса 0, и продолжать движение в цикле, увеличивая счетчик на положительных совпадениях. Затем повторите для «e» ... «u», но он будет намного менее эффективным, чем регулярное выражение или цикл for.

Лучшим подходом было бы просто перебрать строковый символ символом char и либо передать его в существующий оператор switch, либо просмотреть его в некоторой коллекции.

Поскольку вы хотите использовать LINQ, вот как можно было переписать идею выше для цикла, чтобы она соответствовала. Заметьте, эта идея похожа на 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); 
} 

Мой первоначальный ответ регулярное выражение ниже.


Regex подход

Там же лучше регулярное выражение решение, чем тот, который вы используете. Я не уверен, знаете ли вы об этом, и я почувствовал, что это заслуживает публикации. В вопросе № 1 вы сказали «без использования регулярных выражений», но IMHO, который напрямую конфликтует с вопросом №2, где вы спросили, нужно ли вам получить свой собственный метод.

Вы можете сократить свой код, используя Regex.Matches method и Count property на возвращенном MatchCollection:

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; 
} 

EDIT: обновлен с запросом LINQ. Это не сильно отличается от того, что имел OP, просто используя подход «Матчи».

+0

Хорошие моменты по сокращению синтаксиса. Вы также можете удалить foreach с помощью метода LINQ Select: words.Select (input => new {input, Count = rx.Matches (input) .Count}); – HuBeZa

+0

@HuBeZa: спасибо! Я обновил свой код аналогичным запросом LINQ так же, как вы комментировали :) Ваш, конечно, более компактный, используя lamda-запрос; Я сопоставлял запрос понимания OP. –

+0

+0.5 для самого детального ответа, а другой +0.5 для ** игнорировать случай сравнения ** – HuBeZa

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); 

Edit: Как некоторые предложенные здесь, я удалил ToCharArray, я добавил ToLower проверить & также нулевой гласные фильтр.

+2

Вам не нужна строка ToCharArray(), которая реализует IEnumerable

+0

Это неверно, даже если элементы count равны нулю, они будут содержать элементы. –

+0

@Akash: Я думал, это очевидно. Я добавил фильтрацию нулевых гласных. @Yuriy: Вы правы, могу ли я использовать метод расширения w \ o явное литье? Отправьте пример кода. – HuBeZa

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; 
+2

Приятно, но вызов 'ToCharArray' не нужен, потому что' string' реализует 'IEnumerable '. Однако методы расширения 'IEnumerable ' не отображаются в Visual Studio по сомнительным причинам: http://stackoverflow.com/questions/345883/why-doesnt-vs-2008-display-extension-methods-in-intellisense-for -string-class – JulianR

+0

linq не добавляет расширение метода подсчета без ToCharArray .. –

+0

@JulianR, О, я видел это позже, подумал, что VS скрыл его, чтобы он не существовал :) –

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 }; 

Конечно, если вам не нужен список слов, которые имеют гласные (то, что слова не?) И все, что вы хотите сделать, это выводят счетчики, тогда проще всего использовать цикл.

+0

Не все ... это подход, который я использовал в своем ответе: http://stackoverflow.com/questions/1585085/linq -pattern-matching/1585240 # 1585240 –

+1

Нет, не eveyone делает этот комплекс. Я задал вопрос без регулярного выражения, могу ли я его обработать. Вот почему они дают ответы. Спасибо вам много Джорен. – user190560

+0

О, ты прав Ахмад, я почему-то пропустил твое сообщение. – Joren