Как посчитать частоту слов, удалив не-буквы из строки? - PullRequest
2 голосов
/ 06 ноября 2019

У меня есть строка:

var text = @"
I have a long string with a load of words,
and it includes new lines and non-letter characters.
I want to remove all of them and split this text to have one word per line, then I can count how many of each word exist."

Как лучше всего удалить все не-буквенные символы, а затем разбить каждое слово на новую строку, чтобы я мог сохранить и посчитать, сколько из каждогослово есть?

var words = text.Split(' ');

foreach(var word in words)
{
    word.Trim(',','.','-');
}

Я пробовал разные вещи, такие как text.Replace(characters) с whitespace, а затем разделить. Я пробовал Regex (который я бы не использовал).

Я также пытался использовать класс StringBuilder для извлечения символов из текста (строки) и добавления символа только в том случае, если это буква az /AZ.

Также попытался вызвать sb.Replace или sb.Удалите символы, которые я не хочу, прежде чем сохранять их в Словаре. Но я все еще, кажется, получаю символы, которые мне не нужны?

Все, что я пытаюсь, кажется, у меня есть хотя бы один персонаж, которого я не хочу, и не могу понять, почему это не так. не работает

Спасибо!

Ответы [ 3 ]

2 голосов
/ 06 ноября 2019

Использование метода расширения без RegEx и Linq

static public class StringHelper
{
  static public Dictionary<string, int> CountDistinctWords(this string text)
  {
    string str = text.Replace(Environment.NewLine, " ");
    var words = new Dictionary<string, int>();
    var builder = new StringBuilder();
    char charCurrent;
    Action processBuilder = () =>
    {
      var word = builder.ToString();
      if ( !string.IsNullOrEmpty(word) )
        if ( !words.ContainsKey(word) )
          words.Add(word, 1);
        else
          words[word]++;
    };
    for ( int index = 0; index < str.Length; index++ )
    {
      charCurrent = str[index];
      if ( char.IsLetter(charCurrent) )
        builder.Append(charCurrent);
      else
      if ( !char.IsNumber(charCurrent) )
        charCurrent = ' ';
      if ( char.IsWhiteSpace(charCurrent) )
      {
        processBuilder();
        builder.Clear();
      }
    }
    processBuilder();
    return words;
  }
}

Он анализирует все символы, отклоняя все не буквы, создавая словарь для каждого слова с подсчитанным количеством вхождений.

Тест

var result = text.CountDistinctWords();
Console.WriteLine($"Found {result.Count()} distinct words:");
Console.WriteLine();
foreach ( var item in result )
  Console.WriteLine($"{item.Key}: {item.Value}");

Результат по вашему образцу

Found 36 distinct words:

I: 3
have: 2
a: 2
long: 1
string: 1
with: 1
load: 1
of: 3
words: 1
and: 3
it: 1
includes: 1
new: 1
lines: 1
non: 1
letter: 1
characters: 1
want: 1
to: 2
remove: 1
all: 1
them: 1
split: 1
this: 1
text: 1
one: 1
word: 2
per: 1
line: 1
then: 1
can: 1
count: 1
how: 1
many: 1
each: 1
exist: 1
0 голосов
/ 07 ноября 2019

Я верю, что решение со словарем для подсчета частот является наилучшей практикой с точки зрения производительности и ясности. Вот моя версия, которая немного отличается от принятого ответа (я использую String.Split () вместо перебора символов строки):

var text = @"
    I have a long string with a load of words,
    and it includes new lines and non-letter characters.
    I want to remove all of them and split this text to have one word per line, then I       can count how many of each word exist.";

var words = text.Split(new [] {',', '.', '-', ' ', '\n', '\r' }, StringSplitOptions.RemoveEmptyEntries);

var freqByWord = new Dictionary<string, int>();

foreach (var word in words)
{
    if (freqByWord.ContainsKey(word))
    {
        freqByWord[word]++; // we found the same word
    }
    else
    {
        freqByWord.Add(word, 1); // we don't have this one yet
    }
}

foreach (var word in freqByWord.Keys)
{
    Console.WriteLine($"{word}: {freqByWord[word]}");
}

И результаты в значительной степени совпадают:

I: 3
have: 2
a: 2
long: 1
string: 1
with: 1
load: 1
of: 3
words: 1
and: 3
it: 1
includes: 1
new: 1
lines: 1
non: 1
letter: 1
characters: 1
want: 1
to: 2
remove: 1
all: 1
them: 1
split: 1
this: 1
text: 1
one: 1
word: 2
per: 1
line: 1
then: 1
can: 1
count: 1
how: 1
many: 1
each: 1
exist: 1
0 голосов
/ 06 ноября 2019

Использование регулярных выражений без учета буквенных символов. Это также даст вам набор всех слов.

var text = @"
I have a long string with a load of words,
and it includes new lines and non-letter characters.
I want to remove all of them and split this text to have one word per line, then I can count how many of each word exist.";

var words = Regex.Matches(text, @"[A-Za-z ]+").Cast<Match>().SelectMany(n => n.Value.Trim().Split(' '));
int wordCount = words.Count();
...