Menu

Nakov.com logo

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 - [url]
    /// </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 https://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 https://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
Comments (9)

9 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. Sohaib Khan says:

    Thanks for the book mate! Поздрави от САЩ

RSS feed for comments on this post. TrackBack URL

LEAVE A COMMENT