Skip to content
Simple scanner for data streams like STDIN in Swift
Branch: master
Clone or download
Latest commit 1c329bd Feb 17, 2019
Type Name Latest commit message Commit time
Failed to load latest commit information.
StreamScanner.xcodeproj * Update for Swift 4.2 Feb 17, 2019
StreamScanner * Update for Swift 4.2 Feb 17, 2019
StreamScannerTest Swift 3. Feb 6, 2017
StreamScannerTests Swift 3. Feb 6, 2017
.gitignore Initial Jun 27, 2015 Update Feb 6, 2017

Input Stream Scanner

A simple scanner for any kind of file input streams with arbitrary delimiters. Made with Swift, based on NSScanner.

Originally appeared as a necessity to parse the standard input for competitive programming challenges on HackerRank.


For competitive programming

Copy-paste the contents of this tiny sample and enjoy. For more general use cases check out the full version of StreamScanner.swift and see the usage and examples sections below.

As a framework

Compile, link against and don't forget to:

import StreamScanner

As a built-in class

Add StreamScanner.swift file to your project.


For convenience you can declare:

let stdin = StreamScanner.standardInput

and use stdin later on. Spaces and new lines are considered delimiters by default.

Or make your custom stream with:

let stream = StreamScanner(source: FileHandle(forReadingAtPath: "/path/to/file"),
                           delimiters: CharacterSet(charactersIn: "-.:\n"))

Now call read() -> Optional<T> to get the next value from a stream, where T is a type of a variable where you want to read() the stream.

You may call ready() -> Bool to check whether the stream currently contains any data it can parse. Note: the stream may try to grab some data from its source during this check.


Imagine there's a file at /path/to/file with the following contents:

42.times show:not_a_double

And here's one of the ways to scan it with the stream just declared above:

var number: Int?    = //parse an integer at the current position in the stream
var string: String? = //now skip a delimiting dot and parse a string
var double: Double? = //now skip a delimiting colon and try to parse a double

print("\(number) \(string) \(double)")  //Optional(42) Optional("times show") nil

More Examples

Read some arbitrary values of different types from the standard input

    let int:    Int     =,
    let string: String  =,
    let double: Double  =,
    let int64:  Int64   =,
    let float:  Float   =
    print("\(int) \(string) \(double) \(int64) \(float)")


+42 st_ring!
-0.987654321 12345678900


42 st_ring! -0.987654321 12345678900 0.42

Read an array of Int64 of an arbitrary size from the standard input

if var count: Int =
    var array: [Int64] = []

    for _ in 0..<count
        if let integer: Int64 =



1234567890123456789 987654321098765432


[1234567890123456789, 987654321098765432]

Read some strings from the stream in a for loop until it's empty

for name in stdin
    print("Hello, \(name)!")


Chris Ally Joshua


Hello, Chris!
Hello, Ally!
Hello, Joshua!

Read and present the contents of /etc/passwd file

if let input = FileHandle(forReadingAtPath: "/etc/passwd")
    let scanner = StreamScanner(source: input, delimiters: CharacterSet(charactersIn: ":\n"))

    print("User Database:")

    while let line: String =
        //skip any comments
        if !line.hasPrefix("#")
            let username = line

                let valid:    String  =,
                let userId:   Int     =,
                let groupId:  Int     =,
                let gecos:    String  =,
                let home:     String  =,
                let shell:    String  =
                print("User: \t\(username) (\(gecos))")
                print("UID:  \t\(userId)")
                print("GID:  \t\(groupId)")
                print("Home: \t\(home)")


User Database:
User: 	nobody (Unprivileged User)
UID:  	-2
GID:  	-2
Home: 	/var/empty
Shell:	/usr/bin/false
User: 	root (System Administrator)
UID:  	0
GID:  	0
Home: 	/var/root
Shell:	/bin/sh
User: 	daemon (System Services)
UID:  	1
GID:  	1
Home: 	/var/root
Shell:	/usr/bin/false


This toy is free and open.

Creative Commons

You can’t perform that action at this time.