Java - Написание счетчика слогов на основе спецификаций - PullRequest
2 голосов
/ 06 февраля 2012

Спецификация для слога:

Каждая группа смежных гласных (a, e, i, o, u, y) считается одним слогом (например, «ea» в «real» добавляет один слог, но «e ... a» в "царственном" считается как два слога). Однако «е» в конце слова не считается слогом. Также каждое слово имеет хотя бы один слог, даже если в предыдущих правилах счетчик равен нулю.

Мой метод подсчета слогов:

public int countSyllables(String word) {
    int count = 0;
    word = word.toLowerCase();
    for (int i = 0; i < word.length(); i++) {
        if (word.charAt(i) == '\"' || word.charAt(i) == '\'' || word.charAt(i) == '-' || word.charAt(i) == ',' || word.charAt(i) == ')' || word.charAt(i) == '(') {
            word = word.substring(0,i)+word.substring(i+1, word.length());
        }
    }
    boolean isPrevVowel = false;
    for (int j = 0; j < word.length(); j++) {
        if (word.contains("a") || word.contains("e") || word.contains("i") || word.contains("o") || word.contains("u")) {
            if (isVowel(word.charAt(j)) && !((word.charAt(j) == 'e') && (j == word.length()-1))) {
                if (isPrevVowel == false) {
                    count++;
                    isPrevVowel = true;
                }
            } else {
                isPrevVowel = false;
            }
        } else {
            count++;
            break;
        }
    }
    return count;
}

Метод isVowel, который определяет, является ли буква гласной:

public boolean isVowel(char c) {
        if (c == 'a' || c == 'e' || c == 'i' || c == 'o' || c == 'u') {
            return true;
        } else {
            return false;
        }
    }

По словам коллеги, это должно привести к 528 слогам при использовании в этом тексте , но я могу казаться, что он равен этому, и я не знаю, какой из нам правильно. Пожалуйста, помогите мне развить мой метод в правильный алгоритм или помогите показать, что это правильно. Спасибо.

Ответы [ 7 ]

3 голосов
/ 06 февраля 2012

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

Так что если вы измените

 word.toLowerCase();

до

word =  word.toLowerCase();

поможет наверняка.

0 голосов
/ 16 апреля 2017
    private static int countSyllables(String word)
{
    //System.out.print("Counting syllables in " + word + "...");
    int numSyllables = 0;
    boolean newSyllable = true;
    String vowels = "aeiouy";
    char[] cArray = word.toCharArray();
    for (int i = 0; i < cArray.length; i++)
    {
        if (i == cArray.length-1 && Character.toLowerCase(cArray[i]) == 'e' 
                && newSyllable && numSyllables > 0) {
            numSyllables--;
        }
        if (newSyllable && vowels.indexOf(Character.toLowerCase(cArray[i])) >= 0) {
            newSyllable = false;
            numSyllables++;
        }
        else if (vowels.indexOf(Character.toLowerCase(cArray[i])) < 0) {
            newSyllable = true;
        }
    }
    //System.out.println( "found " + numSyllables);
    return numSyllables;
}

Другая реализация находится по ссылке ниже: https://pastebin.com/q6rdyaEd

0 голосов
/ 27 мая 2016

Это моя реализация для подсчета слогов

protected int countSyllables(String word)
{
    // getNumSyllables method in BasicDocument (module 1) and 
    // EfficientDocument (module 2).
    int syllables = 0;
    word = word.toLowerCase();
    if(word.contains("the ")){
        syllables ++;
    }
    String[] split = word.split("e!$|e[?]$|e,|e |e[),]|e$");

    ArrayList<String> tokens = new ArrayList<String>();
    Pattern tokSplitter = Pattern.compile("[aeiouy]+");

    for (int i = 0; i < split.length; i++) {
        String s = split[i];
        Matcher m = tokSplitter.matcher(s);

        while (m.find()) {
            tokens.add(m.group());
        }
    }

    syllables += tokens.size();
    return syllables;
}

У меня отлично работает.

0 голосов
/ 25 сентября 2015

Я только что изобрел новый способ подсчета слогов в Java.

Моя новая библиотека, The Lawrence Style Checker, доступна для просмотра здесь: https://github.com/troywatson/Lawrence-Style-Checker

Я посчитал ваши слоги для каждого слова, используя мою программу, и вывел результаты здесь: http://pastebin.com/LyiBTcbb

С помощью моего словарного метода подсчета слогов я получил: всего 528 слогов.

Это точное число, которое дал спрашивающий, о правильном количестве слогов. Тем не менее, я все еще оспариваю это число по причинам, описанным ниже:

Частота ударов: правильно: 99,4%

Неправильные слова: 2/337 слов

Количество неправильных и неправильных слогов: {смолистый: 4, аардвольф: 3}

Вот мой код:

    Lawrence lawrence = new Lawrence();

    // Turn the text into an array of sentences.
    String sentences = ""
    String[] sentences2 = sentences.split("(?<=[a-z])\\.\\s+");

    int count = 0;

    for (String sentence : sentences2) {
        sentence = sentence.replace("-", " "); // split double words
        for (String word : sentence.split(" ")) {

            // Get rid of punctuation marks and spaces.
            word = lawrence.cleanWord(word);

            // If the word is null, skip it.
            if (word.length() < 1)
                continue;

            // Print out the word and it's syllable on one line.
            System.out.print(word + ",");
            System.out.println(lawrence.getSyllable(word));
            count += lawrence.getSyllable(word);
        }
    }
    System.out.println(count);

бац!

0 голосов
/ 07 февраля 2012

Не прямой ответ (и я бы дал вам один, если бы я думал, что это конструктивно, мой счет около 238 в последней попытке), но я дам вам несколько советов, которые будут иметь решающее значение для создания ответа: *

  1. Разделите вашу проблему: прочитайте строки, затем разбейте строки на слова, затем посчитайте слоги для каждого слова. Послесловие, подсчитайте их по всем строкам.
  2. Подумайте о порядке вещей: сначала найдите все слоги и посчитайте каждый, «прогуливаясь» по слову. Фактор в особых случаях впоследствии.
  3. Во время разработки используйте отладчик для пошагового выполнения кода. Скорее всего, вы делаете типичные ошибки, например toUpperCase(). Лучше найти эти ошибки, никто не создаст идеальный код с первого раза.
  4. Печать в консоль (опытные пользователи используют журнал и сохраняют строки журнала без вывода сообщений в конечной программе). Обязательно отметьте println, используя комментарии, и удалите их из окончательной реализации. Напечатайте такие вещи, как номера строк и количество слогов, чтобы вы могли визуально сравнить их с текстом.
  5. Если вы немного продвинулись, вы можете использовать Matcher.find (регулярные выражения), используя Pattern, чтобы найти слоги. Регулярные выражения - трудные звери, чтобы справиться. Одна из распространенных ошибок - они слишком много делают на ходу.

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

Если вы чувствуете, что повторяете что-то вроде методов isVowel и String.contains(), использующих один и тот же набор символов, вы, вероятно, делаете что-то не так. Повторение в исходном коде - это запах кода.

Используя регулярные выражения, я насчитал около 238 (на 4-м ходу), но на самом деле я не проверял каждый слог (конечно).

1 14
2 17
3 17
4 15
5 15
6 14
7 16
8 19
9 17
10 17
11 16
12 19
13 18
14 15
15 18
16 15
17 16
18 17
19 16
20 17
21 17
22 19
23 17
24 16
25 17
26 17
27 16
28 17
29 15
30 17
31 19
32 23
33 0

 --- total --- 
538
0 голосов
/ 06 февраля 2012

Это должно быть легко выполнимо с некоторыми регулярными выражениями:

Pattern p = Pattern.compile("[aeiouy]+?\w*?[^e]");
String[] result = p.split(WHAT_EVER_THE_INPUT_IS);
result.length

Обратите внимание, что это не проверено.

0 голосов
/ 06 февраля 2012

Я настоятельно рекомендую вам использовать Java String API в полной мере. Например, рассмотрим String.split (регулярное выражение String):

http://docs.oracle.com/javase/7/docs/api/java/lang/String.html#split%28java.lang.String%29

Это принимает строку и регулярное выражение, а затем возвращает массив всех подстрок, используя ваше регулярное выражение в качестве разделителя. Если вы сделаете свое регулярное выражение совпадающим со всеми согласными или пробелами, то в итоге вы получите массив строк, которые либо пусты (и, следовательно, не представляют согласную), либо последовательность гласных (которые представляют согласную). Прикинь последнее, и у тебя будет решение.

Другой альтернативой, которая также использует преимущества API-интерфейса String и регулярных выражений, является replaceAll:

http://docs.oracle.com/javase/7/docs/api/java/lang/String.html#replaceAll%28java.lang.String,%20java.lang.String%29

В этом случае вам нужно регулярное выражение, которое принимает форму [необязательно что-нибудь, что не является гласной] [один или более гласных] [необязательно что-нибудь, что не является гласной]. Запустите это регулярное выражение для вашей строки и замените его одним символом (например, «1»). Конечным результатом является то, что каждый слог будет заменен одним символом. Тогда все, что вам нужно сделать, это String.length (), и вы узнаете, сколько слогов у вас было.

В зависимости от требований вашего решения они могут не работать. Если это домашний вопрос, связанный с разработкой алгоритма, то это почти наверняка не самый предпочтительный ответ, но он имеет преимущество в том, что он лаконичен и хорошо использует встроенные (и, следовательно, высоко оптимизированные) Java API.

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