【问题标题】:Cannot count characters properly无法正确计数字符
【发布时间】:2021-07-04 00:02:29
【问题描述】:

我应该有两个输入:一个是字符,另一个是字符串。

我必须编写一个程序来输出字符在字符串中出现的次数。

最后,我已经能够让程序显示字符输入在字符串中出现的正确次数。

但问题是我必须能够在必要时输出输入字符的复数形式。我不知道我在这里做错了什么,但有时它会在不应该是复数的情况下......基本上,如果那个单词中有0 n,它应该显示0 n......但它显示0恩。

对不起,如果我的描述很糟糕。

import java.util.Scanner;

public class LabProgram {
    public static void main(String[] args) {
      Scanner scnr = new Scanner (System.in);
      char userLetter;
      String userWord;
      
      userLetter = scnr.next().charAt(0);
      userWord = scnr.nextLine();
      
      int wordCount = 0;
      
      for (int i = 0; i < userWord.length(); i=i+1) {
         if (userWord.charAt(i) == userLetter){
            wordCount = wordCount + 1;
         }}
         
      if (wordCount < 2) {
         System.out.println(wordCount + " " + userLetter);
      }
      else if (wordCount == 0) {
         System.out.println(wordCount + " " + userLetter);
      }
      else {
         System.out.println(wordCount + " " + userLetter + "'s");
      }
   }
}

【问题讨论】:

  • 我无法使用您提供的代码重现此问题。你确定这是你正在测试的代码吗?
  • 0 小于 2,或许您可以告诉我们您提供的输入是什么?
  • 正如查理所说,您的代码不包含您所描述的问题。而且它也无法正确读取输入,请参阅:Scanner is skipping nextLine() after using next() or nextFoo()?(但这不会导致所描述的复数问题)
  • 更重要的是......“0 N”是错误的语法。在英语中>正确任何的情况下都不应该有撇号。
  • 最正确的形式是0 "N"s1 "N"2 "N"s(或0 'N's1 'N'2 'N's,如果您愿意的话。)注意:我们使用引号,不是撇号。撇号 - s(通常)表示拥有。

标签: java char


【解决方案1】:

首先避免任何分支的一种替代方法是始终在末尾附加“(s)”。:

System.out.println(wordCount + " " + userLetter + "(s)");

正如 Stephen C 所提到的,撇号“”虽然有时按照您的意思使用,但通常表示 possession,如 n 长度甚至 n 频率。这给我带来了更多选择:

System.out.println(userLetter + "'s frequency" + ": " + wordCount);

System.out.println("The number of times the letter " + userLetter + " appears is " + wordCount);

除了复数的问题,值得注意的是这行执行后:

userLetter = scnr.next().charAt(0)

在输入源中留下一个尾随的新行。这是一个微妙但最常见的编程错误之一。 下一行执行时:

userWord = scnr.nextLine();

它读取尾随的新行并忽略您的第二个输入,您的 nextLine() 返回一个带有空格的字符串。您可以通过将userLetteruserWord 的值打印到控制台来验证这一点。

将前一行改为:

userLetter = scnr.nextLine().charAt(0);

这将使用尾随换行符的输入,而不会留下任何痕迹。

【讨论】:

    【解决方案2】:

    无法重现

    作为commented by Charlie Armstrong,您的问题无法重现。您应该提供MCVE

    您的if 级联 有故障。第一个 if 测试 wordCount 是否小于两个。

    if (wordCount < 2) {         // <--- Condition met for count of 0 or 1. 
    

    零小于二。所以第一个测试成功了,它的代码运行了。

    您对小于零的第二次if 测试是多余的。那一秒if

    else if (wordCount == 0) {   // <--- Never reaches this point for 0 or 1.
    

    …对于 0 或 1 的 wordCount 永远不会执行。第一个测试 if (wordCount &lt; 2) { 将适用于零(或一)的 wordCount,所以它的 System.out.println将运行,if 级联结束。所以我们永远没有机会测试计数是否为零。

    对于“如果该单词中有 0 n,则应显示 0 n”的规则,将代码更改为:

      if ( wordCount > 1 ) {  // For a count of 2 or more.
         System.out.println(wordCount + " " + userLetter + "'s");
      }
      else {  // Else use singular for count of 0 or 1. (Ignoring negative numbers.) 
         System.out.println(wordCount + " " + userLetter);
      }
    

    作为commented by Stephen C,您应该使用带有零和多于一的复数。所以你的逻辑可以减少检查计数是否不是一,在这种情况下你附加复数s。请参阅此答案中的代码示例。

    顺便说一句,我们可以通过 Collections.frequency 让 Java 完成繁重的工作来替换您的大部分代码。继续阅读。

    避免char

    char 类型已过时,甚至无法表示 Unicode 中定义的一半字符。

    Unicode 代码点

    相反,学习在处理单个字符时使用 Unicode code point 整数。

    您可以将字符串转换为IntStream 以获得一系列int 值,每个值都是该字符串中字符的代码点。

    调用boxed 将每个流式int 原语转换为Integer 对象。

    List< Integer > codePoints = "Java".codePoints().boxed().toList() ;  // Prior to Java 16, use `.collect( Collectors.toList() )` in place of `.toList()`.
    Integer codePoint = "a".codePoints().toArray()[0] ;
    int frequency = Collections.frequency( codePoints , codePoint ) ;
    

    频率 = 2

    如果结果不是一个,追加s

    报告结果。

    正如 Stephen C 评论的那样,在正确的英语中,您的目标字母应该用引号括起来,最好是 curly-quotes,不使用任何撇号。附加一个s 表示计数为零或大于一,但省略s 表示结果为一。

    String output = String.valueOf( frequency ) + " ‘" + Character.toString( codePoint ) + "’" ;
    if ( frequency!= 1 ) {
        output = output + "s" ; 
    }
    

    看到这个code run live at IdeOne.com

    2'a's

    import java.util.*;
    import java.lang.*;
    import java.io.*;
    
    import java.util.stream.* ;
    
    class Ideone
    {
        public static void main (String[] args) throws java.lang.Exception
        {
            List< Integer > codePoints = "Java".codePoints().boxed().collect( Collectors.toList() ) ;
            Integer codePoint = "a".codePoints().toArray()[0] ;
            int frequency = Collections.frequency( codePoints , codePoint ) ;
        
            String output = String.valueOf( frequency ) + " ‘" + Character.toString( codePoint ) + "’" ;
            if ( frequency!= 1 ) {
                output = output + "s" ; 
            }
        
            System.out.println( output ) ;
        }
    }
    

    【讨论】:

    • 您能解释一下您的示例中的输入内容吗?如果输入是我输入的字符串,我不能使用 toList()。编译器说“Stream 类型的 toList() 方法未定义”。
    • @SimoneLungarella 对于 Java 15 及更早版本,使用 .collect( Collectors.toList() ) 代替 .toList()
    • @SimoneLungarella My input 是您要确定特定字符出现频率的字符串。我的targetString 在字符串中包含我们将在input 字符串中搜索匹配的单个字符。在自己的代码中,您将根据需要重命名这些变量。
    • 在这种特定情况下,在 java 11 中,“toArray()[0]”的等价物是什么?使用 toArray,因为它返回和 Objects Array,编译器说我不能从 Object 转换为 Integer。
    • @CharlieArmstrong 感谢您的有效批评。我在顶部添加了一个部分来直接解决问题代码中的缺陷。
    【解决方案3】:

    我尝试遵循一些建议的解决方案,但它们对我不起作用,我设法找到了另一个可能符合您意图的解决方案:

    public static void main(String[] args) {
    
        Scanner scnr = new Scanner(System.in);
    
        System.out.print("Enter the word: ");
        String userWord = scnr.nextLine();
    
        System.out.print("Enter the letter: ");
        String userLetter = scnr.nextLine();
    
        List<Character> chars = userWord.chars().mapToObj(c -> (char) c).collect(Collectors.toList());
        Character targetChar = userLetter.charAt(0);
    
        final int frequency = Collections.frequency(chars, targetChar);
    
        if (frequency < 2) {
            System.out.println(frequency + " " + userLetter);
         }
         else if (frequency == 0) {
            System.out.println(frequency + " " + userLetter);
         }
         else {
            System.out.println(frequency + " " + userLetter + "'s");
         }
    
        scnr.close();
    }
    

    【讨论】:

    • 你能用 OP 的代码重现这个问题吗?如果是这样,请描述问题的原因,以便您的答案不仅仅是代码。如果不是,那么你怎么知道你的代码会更好地工作?
    • 我不确定我是否可以重现确切的 OP 问题,发生在我身上的事情是由于 Scanner.next() 方法没有读取换行符而将其留给 nextLine( ) 方法在第一个之后调用。我删除了对“next()”的调用,并使用字符映射来实现相同的结果。
    • 是的,我认为原始代码旨在通过空格将字符与单词分开,而userWord 总是以空格开头。无论哪种方式,获得答案的最佳方式是添加解释。另外,如果是我,我会避免写这样的问题的答案,因为它的写作方式,你不能真正回答这个问题。这使得观众很难认为您的答案是高质量的。只是想传播我得到的一些建议。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-10-05
    • 1970-01-01
    • 2018-05-19
    • 1970-01-01
    • 2020-06-08
    相关资源
    最近更新 更多