3

Specification for a syllable:

Each group of adjacent vowels (a, e, i, o, u, y) counts as one syllable (for example, the "ea" in "real" contributes one syllable, but the "e...a" in "regal" counts as two syllables). However, an "e" at the end of a word doesn't count as a syllable. Also each word has at least one syllable, even if the previous rules give a count of zero.

My countSyllables method:

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

The isVowel method which determines if a letter is a vowel:

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

According to a colleague, this should result in 528 syllables when used on this text, but I can seem to get it to equal that and I don't know which of us is correct. Please help me develop my method into the correct algorithm or help show this is correct. Thank you.

mino
  • 6,340
  • 21
  • 55
  • 72
  • 3
    One problem is that Strings are immutable. Try changing word.toLowerCase(); to word = word.toLowerCase(); and see if that changes anything. – Vincent Ramdhanie Feb 05 '12 at 23:31
  • You also seem to be doing an awful lot of work determining the word limits. Look up the split() method of String here: http://docs.oracle.com/javase/7/docs/api/java/lang/String.html#split%28java.lang.String%29 and that might simplify things for you. – Vincent Ramdhanie Feb 05 '12 at 23:34
  • This does give me a different (and probably more correct!) result of 508 syllables; still not 528 though so is my solution now correct or is the 528 result of my colleague correct and there are still errors in my code? – mino Feb 05 '12 at 23:35
  • If this is homework, please tag it as such--thanks :) – Dave Newton Feb 05 '12 at 23:40
  • I find the code fairly difficult to read; the nesting is pretty deep, and a single method does quite a lot of work. It would be easier to understand, and fix (or not), if there were more methods, each doing fewer things. – Dave Newton Feb 05 '12 at 23:44
  • Seems to me it is a bit strange to say that sea-urchin would have 2 syllables instead of 3 - not that it matters for the input text, but still. – Maarten Bodewes Feb 05 '12 at 23:55
  • The text you gave has 524 syllables not 528 – Vikrant singh Nov 25 '19 at 19:09

7 Answers7

3

One of the problem might be that you call to lover case method on the input, but you do not assign it.

So if you change

 word.toLowerCase();

to

word =  word.toLowerCase();

will help for sure.

1

I have just invented a new way to count syllables in Java.

My new library, The Lawrence Style Checker, can be viewed here: https://github.com/troywatson/Lawrence-Style-Checker

I counted your syllables for every word using my program and displayed the results here: http://pastebin.com/LyiBTcbb

With my dictionary method of counting syllables I got: 528 syllables total.

This is the exact number the questioner gave of the correct number of syllables. Yet I still dispute this number for reasons described below:

Strike rate: 99.4% correct

Words wrong: 2 / 337 words

Words wrong and wrong syllable counts: {resinous: 4, aardwolf: 3}

Here is my code:

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

bam!

troy
  • 147
  • 1
  • 4
  • Lawrence is keyword based, not rule based. The question goes to a checker based on specifications, not keyword based. – Grim May 09 '17 at 19:29
0
    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;
}

Another implementation can be found at below pastebin link: https://pastebin.com/q6rdyaEd

DISHA
  • 141
  • 1
  • 3
0

I would strongly suggest that you use Java's String API to its full ability. For example, consider String.split(String regex):

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

This takes a String, and a regular expression, then returns an array of all the substrings, using your regular expression as a delimeter. If you make your regular expression match all consonants or whitespace, then you will end up with an array of Strings which are either empty (and therefore do not represent a consonant) or a sequence of vowels (which do represent a consonant). Count up the latter, and you will have a solution.

Another alternative which also takes advantage of the String API and regular expressions is replaceAll:

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

In this case, you want a regular expression which takes the form [optional anything which isn't a vowel][one or more vowels][optional anything which isn't a vowel]. Run this regular expression on your String, and replace it with a single character (eg "1"). The end result is that each syllable will be replaced by a single character. Then all you need to do is String.length() and you'll know how many syllables you had.

Depending on the requirements of your solution, these may not work. If this is a homework question relating to algorithm design, this is almost certainly not the preferred answer, but it does have the benefit of being concise and makes good use of the built-in (and therefore highly optimized) Java APIs.

Afshin Moazami
  • 2,003
  • 5
  • 32
  • 54
Erica
  • 2,261
  • 14
  • 21
0

This should be easily doable with some Regex:

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

Please note, that it is untested.

devsnd
  • 6,563
  • 3
  • 39
  • 47
0

Not a direct answer (and I would give you one if I thought it was constructive, my count is about 238 in the last try) but I will give you a few hints that will be fundamental to creating the answer:

  1. Divide up your problem: Read lines, then split the lines up into words, then count the syllables for each word. Afterwords, count them up for all the lines.
  2. Think about the order of things: first find all the syllables, and count each one by "walking" through the word. Factor in the special cases afterwards.
  3. During design, use a debugger to step through your code. Chances are pretty high you make common mistakes like the toUpperCase() method. Better find those errors, nobody will create perfect code the first time around.
  4. Print to console (advanced users use a log and keep the silenced log lines in the final program). Make sure to mark the println's using comments and remove them from the final implementation. Print things like line numbers and syllable counts so you can visually compare them with the text.
  5. If you have advanced a bit, you may use Matcher.find (regular expressions) using a Pattern to find the syllables. Regular expressions are difficult beasts to master. One common mistake is have them do too much in a go.

This way you can quickly scan the text. One of the things you quickly will find out is that you will have to deal with the numbers in the text. So you need to check if a word is actually a word, otherwise, by your rules, it will have at least a single syllable.

If you have the feeling you are repeating things, like the isVowel and String.contains() methods using the same set of characters, you are probably doing something wrong. Repetition in source code is code smell.

Using regexps, I counted about 238 (in the 4th go), but I haven't really checked each and every syllable (of course).

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
Maarten Bodewes
  • 80,169
  • 13
  • 121
  • 225
-1

This is my implementation for counting syllables

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

It works fine for me.

Ima Miri
  • 747
  • 11
  • 28