Y/N 或 y/n 循环

Posted

技术标签:

【中文标题】Y/N 或 y/n 循环【英文标题】:Y/N or y/n in loop 【发布时间】:2012-12-29 05:50:29 【问题描述】:

我无法在循环中实现 Y/N 或 y/n。我设计它的方式是用户可以在循环中使用 Y 和 N 的大写和小写字母作为答案。顺便说一下,这是我的代码,但似乎无法使其工作:

do
        
            Console.WriteLine("\nSelect additional topping/s\n");

            Console.WriteLine("1 - Extra meat: 200");
            Console.WriteLine("2 - Extra cheese: 100");
            Console.WriteLine("3 - Extra veggies: 80\n");

            int selectedTopping = Convert.ToInt32(Console.ReadLine());

            switch (selectedTopping)
            
                case 1:
                    pizza = new MeatToppings(pizza);
                    break;

                case 2:
                    pizza = new CheeseToppings(pizza);
                    break;

                case 3:
                    pizza = new VeggieToppings(pizza);
                    break;

                default:
                    break;
            

            Console.WriteLine("\nAdd more toppings? Y/N");
            

        

        while ((Console.ReadLine() == "Y") || (Console.ReadLine() == "y"));

【问题讨论】:

您的Pizza 课程不应该有addToppings() 方法或可公开访问的浇头列表吗?也许我今天没有喝足够的咖啡,但你的代码对我来说似乎没有意义。 请记住,每次调用Console.ReadLine() 时,程序都会等待用户写入内容并按回车键。你有两次,所以为了继续,用户必须首先输入 Y 并按 enter,然后输入 y 并按 enter。 Tilak 的回答提供了一种简单的方法(当然你也可以降低)。 【参考方案1】:
while ((Console.ReadLine() == "Y") || (Console.ReadLine() == "y"));

这将读取 2 行不同的行,因为您调用了两次 ReadLine()。您需要调用一次并保存该值。

【讨论】:

这确实是 O.P. 代码的一个关键问题,但按照这些思路,Tilak 上面的回答是一个可靠的解决方法。也就是说,将用户输入保存到变量中几乎总是首选方法。 @Devin 确实,Tilak 的方法非常有效。我个人的风格是避免这种事情,所以将输入保存在变量中对我来说更具可读性,并且使代码几乎可以自我记录。 同意,好的代码应该是自我记录的(或者至少我赞同这种理念)。【参考方案2】:

您可以使用ToUpper

while ((Console.ReadLine().ToUpper() == "Y") );

【讨论】:

不鼓励使用 ToUpper/ToLower 进行字符串比较。 The Turkish İ Problem and Why You Should Care 一般情况下是的,但不适用于这个问题。 “Y”没有问题。该问题与字符 i 相关。还有一个工具(FxCop 或 StyleCop)抱怨使用 ToLowerInvariant 支持 'ToUpperInvariant'【参考方案3】:

尝试使用String.EqualsStringComparison

String.Equals(Console.ReadLine(), "y", StringComparison.CurrentCultureIgnoreCase);

来自 MSDN:

CurrentCultureIgnoreCase:使用区分区域性的排序规则、当前区域性比较字符串,并忽略被比较字符串的大小写。

OrdinalIgnoreCase:使用序号排序规则比较字符串,忽略被比较字符串的大小写。

【讨论】:

【参考方案4】:

要检查Yy 忽略大小写,您应该使用string.Equals(string,StringComparison) 重载。

while (Console.ReadLine().Equals("Y", StringComparison.InvariantCultureIgnoreCase));

请在使用ToUpperToLower 之前查看The Turkish İ Problem and Why You Should Care 以进行字符串比较与忽略大小写。

您当前的代码从控制台读取行两次,这就是您的代码等待第二个值的原因。

【讨论】:

这对于检查一个甚至不受土耳其语大小写影响的单个字符来说是多余的。了解土耳其肠衣之类的东西很重要,但知道它何时相关也同样重要。而这里不是。 @dreamlax,怎么会有点矫枉过正?使用 ToLower/ToUpper 将创建一个新字符串,我认为这是一种矫枉过正。是的,土耳其语大小写在这里不是问题,但是对于字符串与忽略大小写的比较,string.Equals 是一个更好的方法 这太过分了,因为它解决了一个不存在的问题,你过度设计了需求。如果创建一个新的单字符字符串是应用程序性能的瓶颈,那么我想你说得有道理。 @dreamlax,我知道性能瓶颈可以忽略不计。它是关于最佳实践的。见Best Practices for Using Strings in the .NET Framework【参考方案5】:

正如 Austin 刚刚指出的,您在 while 循环语句中使用了两次 ReadLine。

值得一提的是尽量遵循模块化规则,这将有助于加快实现和调试我们的代码。

我已经有一段时间没有进行任何 C# 编程了,所以用 Java 风格进行 sudo 编码。

由于它是命令行编程,您可能需要多次验证用户输入。我要做的一件事是创建一个实用程序类来包含常见的用户输入任务。

public class TerminalUtil 
    private TerminalUtil() 

    public static boolean isYes(String msg) return (msg.ToUpper() == "Y" || msg.ToUpper() == "YES"); 
    public static boolean isNo(String msg) return (msg.ToUpper() == "N" || msg.ToUpper() == "NO"); 
   // You also might want basic conditionals to check if string is numeric or contains letters.

    // I like using recursion for command line utilities so having a method that can re-print messages is handy
    public static void display(String[] messages)
        for(String msg : messages)
            Console.WriteLine(msg);
        
    

    public static boolean enterYesOrNo(String[] messages, String[] errorMessages)
        display(messages)
        String input = Console.ReadLine();
        if( isYes(input) )
            return true;
         else if( isNo(input) ) 
            return false; 
         else 
             display(errorMessages); // Maybe something like, you didn't enter a yes or no value.
             enterYesOrNo(messages, errorMessages); // Recursive loop to try again.
        

    

这是订购披萨的代码的样子

public class OrderPizza
    public static int selectToppings()
        String[] message = new String[4];
        message[0] = ("\nSelect additional topping/s\n");
        message[1] = ("1 - Extra meat: 200");
        message[2] = ("2 - Extra cheese: 100");
        message[3] = ("3 - Extra veggies: 80\n");

       int option =  TerminalUtils.entryNumeric(message, "You entered an non-numeric character, try again" );
       if( option > 0 && option <= 3 )
           return option;
        else 
          Console.WriteLine("Number must be between 1 - 3, try again.");
          return selectToppings();
       
    

    public static Pizza order()
        Pizza pizza = new Pizza();

        while(true)
            int toppingCode = selectTopping();
            pizza.addTopping(toppingCode);
            if(!TerminalUtil.enterYesOrNo("\nAdd more toppings? Y/N", "Please enter a 'Y'es or 'N'o") )
                break;
            
        
    

这样做的主要好处是减少了while循环的业务逻辑,您可以在TerminalUtils中重用代码。此外,这绝不是一个优雅的解决方案,我很懒惰,现在是 IRL 凌晨 3 点,但它应该足以让球滚动。

您可能应该重新考虑做的一件事是使用整数代码来表示浇头。使用枚举可能会使事情更容易实现。

我还注意到您添加了三种不同类型的比萨饼,我假设它们是三个单独的对象。

由于您正在循环向比萨饼添加配料,因此请创建一个抽象的比萨饼类。通过这种方式,您可以对其进行扩展,例如意大利辣香肠或奶酪等通用的预制比萨饼,并在您希望客户定制他们的订单时使用抽象比萨饼类。

【讨论】:

【参考方案6】:

我没有找到比以下更好的方法:

while ( str!="N" )

    str = Console.ReadLine();
    str = str.ToUpper();
    if (str == "Y");
       break;
;

【讨论】:

以上是关于Y/N 或 y/n 循环的主要内容,如果未能解决你的问题,请参考以下文章

如何仅使用for循环在matlab中裁剪图像? [复制]

while循环保持打印和重复,我的getch出了什么问题? [重复]

如何打破多个循环?

循环和控制语句

8猜年龄2

Java 中的分支和循环(中断和继续)