Java Подсчет количества вхождений слова в строку - PullRequest
5 голосов
/ 14 апреля 2010

У меня большой текстовый файл, из которого я читаю, и мне нужно выяснить, сколько раз встречаются некоторые слова. Например, слово the. Я делаю эту строку построчно, каждая строка - строка.

Мне нужно убедиться, что я считаю только легальные the - the в other не будет учитываться. Это означает, что я знаю, что мне нужно каким-то образом использовать регулярные выражения. То, что я пытался до сих пор, это:

numSpace += line.split("[^a-z]the[^a-z]").length;  

Я понимаю, что на данный момент регулярное выражение может быть неправильным, но я пытался без этого и просто пытался найти вхождения слова the, и я тоже получаю неправильные числа. У меня сложилось впечатление, что это разделит строку на массив, и сколько раз этот массив был разбит, сколько раз слово находится в строке. Любые идеи, я был бы признателен.

Обновление: Учитывая некоторые идеи, я придумал это:

numThe += line.split("[^a-zA-Z][Tt]he[^a-zA-Z]", -1).length - 1;

Хотя все еще получаю странные цифры. Я смог получить точное общее количество (без регулярного выражения), теперь моя проблема с регулярным выражением.

Ответы [ 8 ]

9 голосов
/ 14 апреля 2010

Использование split для подсчета - не самый эффективный способ, но если вы настаиваете на этом, то правильный путь таков:

haystack.split(needle, -1).length -1                            

Если вы не установите limit на -1, split по умолчанию будет 0, что удаляет завершающие пустые строки, что портит ваш счет.

С API :

Параметр limit определяет количество применений шаблона и, следовательно, влияет на длину результирующего массива. [...] Если n равно нулю, то [...] завершающие пустые строки будут отброшены.

Вам также необходимо вычесть 1 из length массива, поскольку вхождения N разделителя разбивают строку на N+1 частей.


Что касается самого регулярного выражения (то есть needle), вы можете использовать \b якоря границы слова вокруг word. Если вы разрешите word содержать метасимволы (например, число вхождений "$US"), вы можете Pattern.quote it.


Я придумал это:

numThe += line.split("[^a-zA-Z][Tt]he[^a-zA-Z]", -1).length - 1;

Хотя все еще получаются странные цифры. Я смог получить точное общее количество (без регулярного выражения), теперь моя проблема с регулярным выражением.

Теперь проблема в том, что вы не учитываете [Tt]he, которое появляется как первое или последнее слово, потому что регулярное выражение говорит, что перед ним должен следовать какой-то символ, за которым следует [^a-zA-Z] (т.е. Ваш матч должен быть длиной 5!). Вы не допускаете случай, когда не персонаж вообще!

Вместо этого вы можете попробовать что-то вроде этого:

"(^|[^a-zA-Z])[Tt]he([^a-zA-Z]|$)"

Это не самое лаконичное решение, но оно работает.

Нечто подобное (с использованием негативные выражения ) также работает:

"(?<![a-zA-Z])[Tt]he(?![^a-zA-Z])"

Преимущество состоит в сопоставлении с [Tt]he, без каких-либо дополнительных символов вокруг него, как это было в предыдущем решении. Это актуально в случае, если вы действительно хотите обработать токены, возвращенные split, потому что в этом случае разделитель не «крадет» что-либо из токенов.


Non- split

Хотя использование split для подсчета довольно удобно, это не самый эффективный (например, он выполняет все виды работы, чтобы вернуть те строки, которые вы отбрасываете). Тот факт, что, как вы сказали, вы рассчитываете построчно, означает, что шаблон также придется перекомпилировать и отбрасывать каждую строку.

Более эффективный способ - использовать те же регулярные выражения, которые вы использовали ранее, и выполнять обычные Pattern.compile и while (matcher.find()) count++;

.
4 голосов
/ 22 февраля 2014

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

     Pattern pattern = Pattern.compile("Thewordyouwant");
        Matcher matcher = pattern.matcher(string);
        int count = 0;
        while(matcher.find())
            count++;
4 голосов
/ 14 апреля 2010

Разделение строк звучит как много накладных расходов, просто чтобы узнать количество вхождений в файле. Вы можете использовать String.indexOf(String, int) для рекурсивного просмотра всей строки / файла, например:

int occurrences = 0;
int index = 0;
while (index < s.length() && (index = s.indexOf("the", index)) >= 0) {
    occurrences++;
    index + 3; //length of 'the'
}
4 голосов
/ 14 апреля 2010

Почему бы не запустить вашу строку через Java StringTokenizer , тогда вы можете разбить слова не только по пробелам, но и по запятым и другим пунктуациям. Просто пробежитесь по своим токенам и посчитайте, что встречается каждое «или» слово, которое вы хотите.

Было бы очень легко расширить это немного и составить карту, в которой каждое слово было бы ключевым и сохраняло счет каждого использования слова. Также вам может понадобиться пропустить каждое слово через функцию, чтобы основа слово, чтобы вы могли посчитать более полезную вещь, чем просто слова.

2 голосов
/ 14 апреля 2010

Я думаю, что это область, где юнит-тесты действительно могут помочь. Некоторое время назад у меня была похожая вещь, когда я хотел разбить строку несколькими сложными способами и создать ряд тестов, каждый из которых проверялся на другой исходной строке, помог мне изолировать регулярное выражение и также быстро увидеть, когда Я неправильно понял.

Конечно, если бы вы дали нам пример тестовой строки и результат, это помогло бы нам дать вам лучшие ответы.

1 голос
/ 14 апреля 2010

Вы можете попробовать использовать границу слова \ b в регулярном выражении:

\bthe\b

Также размер массива, возвращаемого split, будет на 1 больше, чем фактическое количество вхождений слова в string.

0 голосов
/ 29 апреля 2012
public class OccurenceOfWords {
 public static void main(String args[]){    
   String file = "c:\\customer1.txt";
   TreeMap <String ,Integer> index = new TreeMap();

    String []list = null;
      try(    FileReader fr = new FileReader(file);//using arm jdk 7.0 feature
                BufferedReader br = new BufferedReader(fr))
        {
            String line = br.readLine();
            while(line!= null){
                list = line.split("[ \n\t\r:;',.(){}]");
                for(int i = 0 ; i < list.length;i++)
                {
                  String word = list[i].toLowerCase();  
                    if(word.length() != 0)
                    {
                        if(index.get(word)== null)
                        { index.put(word,1);
                         }
                        else    
                        {
                            int occur = index.get(word).intValue();
                            occur++;
                            index.put(word, occur);
                        }
                        line = br.readLine();
                    }  
                }
         }}
                         catch(Exception ex){
                       System.out.println(ex.getMessage());
                       }
                    for(String item : index.keySet()){
                        int repeats = index.get(item).intValue();
                       System.out.printf("\n%10s\t%d",item,repeats);
                 }   
             }               
  }
0 голосов
/ 14 апреля 2010

Поиск слова "the" с использованием boyer-moore [в оставшейся части строки после попадания] и подсчет числа случаев?

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