【问题标题】:Java - Writing a syllable counter based on specificationsJava - 根据规范编写音节计数器
【发布时间】:2012-02-27 13:39:06
【问题描述】:

音节说明:

每组相邻的元音 (a, e, i, o, u, y) 算作一个音节(例如,“real”中的“ea”贡献一个音节,但“e...a”在“富豪”中算作两个音节)。但是,单词末尾的“e”不算作音节。即使前面的规则给出的计数为零,每个单词也至少有一个音节。

我的 countSyllables 方法:

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

据一位同事说,这在this text 上使用时应该会产生 528 个音节,但我似乎可以让它等于那个,我不知道我们谁是正确的。请帮助我将我的方法开发成正确的算法或帮助证明这是正确的。谢谢。

【问题讨论】:

  • 一个问题是字符串是不可变的。尝试改变 word.toLowerCase(); to word = word.toLowerCase();看看这是否会改变什么。
  • 您似乎也在做大量工作来确定字数限制。在此处查找 String 的 split() 方法:docs.oracle.com/javase/7/docs/api/java/lang/…,这可能会为您简化事情。
  • 这确实给了我一个不同的(而且可能更正确!)508个音节的结果;仍然不是 528,但我的解决方案现在是正确的还是我同事的 528 结果正确并且我的代码中仍然存在错误?
  • 如果这是作业,请标记它--谢谢:)
  • 我发现代码相当难以阅读;嵌套很深,一个方法可以做很多工作。如果有更多方法,每个方法做的事情更少,就会更容易理解和修复(或不修复)。

标签: java string methods


【解决方案1】:

其中一个问题可能是您在输入上调用了情人案例方法,但您没有分配它。

所以如果你改变了

 word.toLowerCase();

word =  word.toLowerCase();

肯定会有所帮助。

【讨论】:

    【解决方案2】:

    我刚刚发明了一种在 Java 中计算音节的新方法。

    我的新图书馆,劳伦斯风格检查器,可以在这里查看:https://github.com/troywatson/Lawrence-Style-Checker

    我使用我的程序计算了每个单词的音节并在此处显示结果:http://pastebin.com/LyiBTcbb

    使用我的字典计算音节的方法,我得到:总共 528 个音节。

    这是提问者给出的正确音节数的确切数字。然而,我仍然对这个数字提出异议,原因如下:

    命中率:99.4% 正确

    单词错误:2 / 337 个单词

    单词错错音节数:{resinous: 4, aardwolf: 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);
    

    砰!

    【讨论】:

    • Lawrence 是基于关键字的,而不是基于规则的。问题是基于规范而不是基于关键字的检查器。
    【解决方案3】:

    使用一些正则表达式应该很容易做到这一点:

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

    请注意,它未经测试。

    【讨论】:

      【解决方案4】:

      不是一个直接的答案(如果我认为它是建设性的,我会给你一个,我的计数在最后一次尝试中约为 238),但我会给你一些提示,这对于创建答案至关重要:

      1. 划分你的问题:阅读行,然后将行拆分成单词,然后计算每个单词的音节。后记,计算所有的行。
      2. 想想事物的顺序:首先找到所有的音节,然后通过“遍历”单词来计算每个音节。事后考虑特殊情况。
      3. 在设计期间,使用调试器单步调试您的代码。您犯像toUpperCase() 方法这样的常见错误的可能性非常高。最好找出那些错误,没有人会在第一时间就创造出完美的代码。
      4. 打印到控制台(高级用户使用日志并将静音日志行保留在最终程序中)。确保使用 cmets 标记 println 并将它们从最终实现中删除。打印行号和音节数等内容,以便您可以直观地将它们与文本进行比较。
      5. 如果你有一点进步,你可以使用Matcher.find(正则表达式)和Pattern来查找音节。正则表达式是难以掌握的野兽。一个常见的错误是让他们一次做太多事情。

      这样您可以快速扫描文本。您很快会发现的一件事是您必须处理文本中的数字。所以你需要检查一个 word 是否真的是一个词,否则,根据你的规则,它至少有一个音节。

      如果您感觉自己在重复某些事情,例如使用同一组字符的 isVowelString.contains() 方法,那么您可能做错了什么。源代码中的重复是代码异味。

      使用正则表达式,我数了大约 238 个(第四次),但我并没有真正检查每个音节(当然)。

      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
      

      【讨论】:

        【解决方案5】:

        我强烈建议您充分利用 Java 的 String API。例如,考虑 String.split(String regex):

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

        这需要一个字符串和一个正则表达式,然后返回一个包含所有子字符串的数组,使用您的正则表达式作为分隔符。如果你让你的正则表达式匹配所有的辅音或空格,那么你最终会得到一个字符串数组,它们要么是空的(因此不代表辅音),要么是元音序列(代表辅音)。算上后者,你就会有一个解决方案。

        另一个利用 String API 和正则表达式的替代方法是 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。

        【讨论】:

          【解决方案6】:
              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;
          }
          

          另一个实现可以在下面的 pastebin 链接中找到: https://pastebin.com/q6rdyaEd

          【讨论】:

            【解决方案7】:

            这是我计算音节的实现

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

            对我来说很好用。

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 2011-09-19
              • 1970-01-01
              • 2011-01-20
              • 1970-01-01
              • 2019-02-23
              • 2017-09-07
              • 2013-01-18
              • 1970-01-01
              相关资源
              最近更新 更多