Menu

 

Thoughts on Software Engineering

Simplified Console Input Class for C#, Similar to “cin >> a >> b” in C++ and java.util.Scanner

Recently I was again asked how do we perform “cin >> a >> b” in C# or how we can enter a sequence of numbers from the console in C#. In C++ we have very powerful class called “cin” (more correctly std::cin located in the standard library “iosteam”) that overloads the >> operator and allows entering anything from the standard input (stdin): numbers, characters, strings and other data types.

I searched for “cin in C#” and found nothing similar to “std::cin” for C#, so I needed to write such a class.

The Nakov.IO.Cin Class – “cin” Functionality for C# / .NET

Initially I had an idea to implement my C# “cin” class exactly like in C++. Unfortunately this was impossible because the C# language has certain limitations:

  • You cannot override the >> operator in C# for any type except int
  • You cannot override the >> operator in C# for output / by-ref types (e.g. out int, ref int)
  • You cannot add extension methods to the Console class because it is static (so additions like Console.Cin, Console.NextInt(), Console.In << x << b and Console.Cin.NextInt() cannot be added to it)

Finally I decided to implement my C# console simplifies reader it in a way similar to the Java syntax used in the java.util.Scanner class. See the code below:

namespace Nakov.IO
{
    using System;
    using System.Text;
    using System.Globalization;

    /// <summary>
    /// Console input helper for C# and .NET. Allows simplified reading of numbers and string
    /// tokens from the console in a way similar to "cin" in C++ and java.util.Scanner in Java.
    /// </summary>
    /// 
    /// <copyright>
    /// (c) Svetlin Nakov, 2011 - http://www.nakov.com
    /// </copyright>
    /// 
    /// <example>
    /// // In C++ we will use "cin >> x >> y;"
    /// // Using Nakov.IO.Cin we can do the same as follows:
    /// int x = Cin.NextInt();
    /// double y = Cin.NextDouble();
    /// </example>
    /// 
    public static class Cin
    {
        /// <summary>
        /// Reads a string token from the console
        /// skipping any leading and trailing whitespace.
        /// </summary>
        public static string NextToken()
        {
            StringBuilder tokenChars = new StringBuilder();
            bool tokenFinished = false;
            bool skipWhiteSpaceMode = true;
            while (!tokenFinished)
            {
                int nextChar = Console.Read();
                if (nextChar == -1)
                {
                    // End of stream reached
                    tokenFinished = true;
                }
                else
                {
                    char ch = (char)nextChar;
                    if (char.IsWhiteSpace(ch))
                    {
                        // Whitespace reached (' ', '\r', '\n', '\t') -->
                        // skip it if it is a leading whitespace
                        // or stop reading anymore if it is trailing
                        if (!skipWhiteSpaceMode)
                        {
                            tokenFinished = true;
                            if (ch == '\r' && (Environment.NewLine == "\r\n"))
                            {
                                // Reached '\r' in Windows --> skip the next '\n'
                                Console.Read();
                            }
                        }
                    }
                    else
                    {
                        // Character reached --> append it to the output
                        skipWhiteSpaceMode = false;
                        tokenChars.Append(ch);
                    }
                }
            }
            
            string token = tokenChars.ToString();
            return token;
        }

        /// <summary>
        /// Reads an integer number from the console
        /// skipping any leading and trailing whitespace.
        /// </summary>
        public static int NextInt()
        {
            string token = Cin.NextToken();
            return int.Parse(token);
        }

        /// <summary>
        /// Reads a floating-point number from the console
        /// skipping any leading and trailing whitespace.
        /// </summary>
        /// <param name="acceptAnyDecimalSeparator">
        /// Specifies whether to accept any decimal separator
        /// ("." and ",") or the system's default separator only.
        /// </param>
        public static double NextDouble(bool acceptAnyDecimalSeparator = true)
        {
            string token = Cin.NextToken();
            if (acceptAnyDecimalSeparator)
            {
                token = token.Replace(',', '.');
                double result = double.Parse(token, CultureInfo.InvariantCulture);
                return result;
            }
            else
            {
                double result = double.Parse(token);
                return result;
            }
        }

        /// <summary>
        /// Reads a decimal number from the console
        /// skipping any leading and trailing whitespace.
        /// </summary>
        /// <param name="acceptAnyDecimalSeparator">
        /// Specifies whether to accept any decimal separator
        /// ("." and ",") or the system's default separator only.
        /// </param>
        public static decimal NextDecimal(bool acceptAnyDecimalSeparator = true)
        {
            string token = Cin.NextToken();
            if (acceptAnyDecimalSeparator)
            {
                token = token.Replace(',', '.');
                decimal result = decimal.Parse(token, CultureInfo.InvariantCulture);
                return result;
            }
            else
            {
                decimal result = decimal.Parse(token);
                return result;
            }
        }
    }
}

How Cin.NextDouble() Works?

My class Nakov.IO.Cin allows simplified entering string tokens, integer numbers, floating-point numbers and decimal numbers in C# from the standard input (the console). When reading a sequence of numbers, we can separate them with a single space, multiple spaces, new line separators or any other sequence of whitespace characters: spaces, tabs, new lines (\n, \r\n), etc.

In addition Nakov.IO.Cin solves the culture-specific problem with the decimal point separator which may be “,” in some countries (like Bulgaria) and “.” in other countries (like USA and Canada). The Cin.NextDouble() and Cin.NextDecimal() methods accept a Boolean parameter which specifies whether the numbers should be parsed using the default decimal separator (specified in the regional settings in Windows) or by accepting both separators: “.” and “,”. By default both decimal separators are accepted when entering numbers by Nakov.IO.Cin.NextDouble() and Nakov.IO.Cin.NextDecimal().

Using the Nakov.IO.Cin Class – Example

In the below example I show how to use the class “Nakov.IO.Cin” to enter integer numbers, floating-point numbers, decimal numbers and string tokens:

using System;
using Nakov.IO; // see http://www.nakov.com/tags/cin

public class CinExample
{
    static void Main()
    {
        Console.Write("Enter your name: ");
        string name = Console.ReadLine();

        Console.Write("Enter two integers x and y separated by whitespace: ");
        // cin >> x >> y;
        int x = Cin.NextInt();
        double y = Cin.NextDouble();

        Console.Write("Enter your age: ");
        int age = int.Parse(Console.ReadLine());

        Console.WriteLine("Name: {0}, Age: {1}", name, age);
        Console.WriteLine("x={0}, y={1}", x, y);

        Console.Write("Enter a positive integer number N: ");
        int n = Cin.NextInt();

        Console.Write("Enter N decimal numbers separated by a space: ");
        decimal[] numbers = new decimal[n];
        for (int i = 0; i < n; i++)
        {
            numbers[i] = Cin.NextDecimal();
        }

        Console.Write("The numbers in ascending order: ");
        Array.Sort(numbers);
        for (int i = 0; i < n; i++)
        {
            Console.Write(numbers[i]);
            Console.Write(' ');
        }
        Console.WriteLine();

        Console.WriteLine("Enter two strings seperated by a space: ");
        string firstStr = Cin.NextToken();
        string secondStr = Cin.NextToken();
        Console.WriteLine("First str={0}", firstStr);
        Console.WriteLine("Second str={0}", secondStr);
    }
}

Translating from C++ “cin” to C# Using the C# “cin” Class

Once you have included the class Nakov.IO.Cin to your C# / VB.NET project, you could translate the following C++ program into C#:

Sample C++ code entering a number N and a sequence of N integer numbers, separated by a space (or any other sequence of whitespace characters):

#include <iostream>

using namespace std;

int main()
{
    int n;
    cin >> n;

    int* numbers = new int[n];
    for (int i = 0; i < n; i++)
    {
        cin >> numbers[i];
    }

    for (int i = 0; i < n; i++)
    {
        cout << numbers[i] << ' ';
    }
}

The same code written in C# using the C# “cin” class (Nakov.IO.Cin) is as follows:

using System;
using Nakov.IO; // see http://www.nakov.com/tags/cin

public class EnteringNumbers
{
    static void Main()
    {
        int n;
        n = Cin.NextInt();

        int[] numbers = new int[n];
        for (int i = 0; i < n; i++)
        {
            numbers[i] = Cin.NextInt();
        }

        for (int i = 0; i < n; i++)
        {
            Console.Write(numbers[i] + " ");
        }
    }
}

With both the programs (the C++ and the C# one) you are free to enter all the requested numbers on a single line (e.g. “3   1 –2   3”) or on separate lines (e.g. “\r\n 3 \r\n   1 \t –2 \r\n\r\n  3”)) and they will be parsed correctly, as expected.

Download the Nakov.IO.Cin Class

Download the full source code and examples: Nakov.IO.Cin.zip.

Download the C# class source code only: Cin.cs.

Nakov.IO.Cin at NuGet

The Nakov.IO.Cin library is also available as NuGet package: https://www.nuget.org/packages/Nakov.IO.Cin/. To install it to your project from Visual Studio, use the “Package Manager Console” and execute the following command:

Install-Package Nakov.IO.Cin
Previews (17,865), Views (2,686), Comments (11)

11 Responses to “Simplified Console Input Class for C#, Similar to “cin >> a >> b” in C++ and java.util.Scanner”

  1. Росен says:

    Без дори един юнит тест?

  2. nakov says:

    Не съм писал тестове, нямах достатъчно време. Някой ден ще ги напиша…

  3. Johnny says:

    По-скоро трябваше примерите да са с Generic методи –
    Cin.Next< int >();
    Cin.Next< double >();
    и т.н.

  4. Johnny says:

    Между Next-а и () трябваше да има ъглови скоби с type argument (int, double, decimal, etc.) … но блога реши да ги цензурира

  5. nakov says:

    Мдаа, интересно ще се получи с generics.

  6. francis says:

    thanks so much for publishing the book “programing with c” its been a helpful book.

  7. jimmy says:

    Fantastic NakovClass, I need more of your classes to get familiar with C#…I am an old C++….Thank you!

  8. ルイヴィトン スーパーコピー「バッグ色は手触りがいいが、触ってみると、週囲の姉妹はこの綺麗、最近ずっと忙しくて、長い時間がかかりました、いい感じ ヴィトン スーパーコピー ルイヴィトンキーケース コピー当店ルイヴィトン 偽物は創業9年以上の老舗です。業界の長い歴史から言えばまだまだですが、創業 9 年以上の実績と信頼のあるお店です。全世界通信販売は6年前から行っております。さらに1年間で約数万件の販売実績があります。ルイヴィトン スーパーコピー 販売専門ショップです!ルイヴィトン コピー ブランドバッグ、財布、アクセサリー、手帳、ベルト、靴、腕時計、ネクタイ、スカーフなどを揃っております、日本国内最高級のルイヴィトン偽物ブランド激安販売! http://www.msnbrand.com/goods-copy-4780.html

  9. スーパーコピーロレックス,品質保証も安心のロレックスコピー通販サイトHoshiwatch.CoM.ロレックススーパーコピー時計続々入荷中!!!当店は本物と区分けが付かないようなN品スーパーコピーロレックス腕時計等を扱っております. http://www.gginza.com/%E3%82%A2%E3%83%90%E3%82%A6%E3%83%88/item_13.html

  10. スーパーコピーブランド激安ショッピングモール!ブランドスーパーコピー品ごとにぱっと見て全然違わないほどの外観を持ち、手触りも同じである。当店スーパーコピーブランド商品とともに、高品質と安心をお届けいたします!スーパーコピー 代引きN品をご 購入の方は、こちらへ.弊社は正規品と同等品質のコピー品を低価で お客様に提供します!すべての商品は品質2年無料保証です。100%実物写真ですし、品質が完璧です!”ブランド財布偽物財布コピー ルイヴィトン財布偽物良質なスーパーコピー品を創造します!当社のスーパーコピー代引き、スーコピー腕時計は他社のものより品質がよくて、価格も安いです http://www.brandiwc.com/brand-super-19-copy-0.html

RSS feed for comments on this post. TrackBack URL

LEAVE A COMMENT