#competitive-programming #white-space #parser #input #delimited #reading #intended

token-read

A library for reading whitespace delimited files intended for competitive programming

4 releases

0.2.0 Jun 2, 2023
0.1.2 Jan 13, 2023
0.1.1 Jan 12, 2023
0.1.0 Jan 11, 2023

#1285 in Text processing

Download history 19/week @ 2024-02-26 18/week @ 2024-03-11 62/week @ 2024-04-01

80 downloads per month

MIT/Apache

28KB
534 lines

token-read

Crates.io version License GitHub last commit GitHub issues

This is a simple crate that allows for easy parsing of whitespace delimited files.

It is primarily intended for competitive programming, where such files are commonly used as inputs due to being easy to parse in C and C++. This crate aims to bring this ease to Rust.

Examples

For complete programs, see the examples in the source repository.

Initialization

A TokenReader can be constructed from any type implementing BufRead, such as a file, standard input or a byte slice.

The easiest way to handle errors is to use anyhow.

use std::io::stdin;

use anyhow::Result;
use token_read::TokenReader;

fn main() -> Result<()> {
    let mut input = TokenReader::new(stdin().lock());

    // Do IO and computation

    Ok(())
}

Reading one or more values

A tuple of one or more values of any type implementing FromStr can be read using the line function.

let (budget, ): (u64, ) = input.line()?;
let (product, cost): (String, u64) = input.line()?;

Sample input

10000
Sandwich 80

Reading a raw line

In order to read a line without any modifications, you can use the line_raw function.

let sentence: String = input.line_raw()?;

Sample input

All human beings are born free and equal in dignity and rights.

Reading a collection of values

The line function can also be used to read a variable amount values of a type implementing FromStr into most standard collections.

let temperatures: Vec<f64> = input.line()?;
let allowed_letters: HashSet<char> = input.line()?;

Sample input

18.7 19.2 19.4 18.9
A B E I J M N

Reading several lines

The take function can be used to create an iterator consuming a specific number of lines. You can use it to make a simple for loop.

let (city_count, ): (usize, ) = input.line()?;

for city in input.take(city_count) {
    let (name, population): (String, u64) = city?;
}

Alternatively, it can be collected into any data structure.

let (city_count, ): (usize, ) = input.line()?;
let cities: Vec<(String, u64)> = input.take(city_count).collect::<Result<_, _>>()?;

In cases where the input doesn't need to be stored in memory, take_count can be used instead, as it allows larger line counts than fit in a usize:

let (city_count, ): (u64, ) = input.line()?;

for city in input.take_count(city_count) {
    let (name, population): (String, u64) = city?;
}

Sample input

3
Prague 1309000
New York 8468000
Tokio 13960000

Installation

This crate is available from crates.io. To install, simply run:

cargo add token-read

Dependencies

~0.4–0.8MB
~19K SLoC