char-positions

Crates.iochar-positions
lib.rschar-positions
version0.1.0
created_at2025-06-25 23:15:18.280539+00
updated_at2025-06-25 23:15:18.280539+00
descriptionIterate chars and their positions, i.e. line, column, and byte ranges
homepage
repositoryhttps://github.com/vallentin/char-positions
max_upload_size
id1726642
size24,388
Christian Vallentin (vallentin)

documentation

https://docs.rs/char-positions

README

char-positions

Similar to the standard library's .char_indicies(), but instead of only producing the start byte position. This library implements .char_positions(), which can produce any combination of line, column, start byte, and end byte position.

As an example use text.char_positions::<LineCol>() to get the line and column of each char. Use LineColByteRange to additionally get the byte range, or just Line to simply get the line number.

Example

use char_positions::{CharPositionsExt, LineCol};

let text = "Hello šŸ‘‹\nWorld šŸŒ\nšŸ¦€šŸ¦€";

for (LineCol(line, col), c) in text.char_positions() {
    println!("[Ln {line}, Col {col}] {c:?}");
}

Which will output:

[Ln 1, Col 1] 'H'
[Ln 1, Col 2] 'e'
[Ln 1, Col 3] 'l'
[Ln 1, Col 4] 'l'
[Ln 1, Col 5] 'o'
[Ln 1, Col 6] ' '
[Ln 1, Col 7] 'šŸ‘‹'
[Ln 1, Col 8] '\n'
[Ln 2, Col 1] 'W'
[Ln 2, Col 2] 'o'
[Ln 2, Col 3] 'r'
[Ln 2, Col 4] 'l'
[Ln 2, Col 5] 'd'
[Ln 2, Col 6] ' '
[Ln 2, Col 7] 'šŸŒ'
[Ln 2, Col 8] '\n'
[Ln 3, Col 1] 'šŸ¦€'
[Ln 3, Col 2] 'šŸ¦€'

Supported

.char_positions::<T>() Produces
usize Start byte index (same as .char_indicies())
std::ops::Range<usize> Start byte and end byte index, i.e. &text[range] is the char
LineColByteRange Line number, column number, and byte range
LineCol Line number and column number
Line Line number
Col Column number
ByteRange Same as using std::ops::Range<usize>
ByteStart Start byte index (same as .char_indicies())
ByteEnd End byte index
Tuples are also supported, e.g.
(Line,) Produces the tuple
(Line, Col) Produces the tuple
(Line, Col, ByteStart, ByteEnd) Produces the tuple
etc.

Example - LineColByteRange

use char_positions::{CharPositionsExt, LineColByteRange};

let text = "Hello šŸ‘‹\nWorld šŸŒ\nšŸ¦€šŸ¦€";

let mut iter = text
    .char_positions::<LineColByteRange>()
    .map(|(LineColByteRange(line, col, range), c)| (line, col, range, c));

assert_eq!(iter.next(), Some((1, 1, 0..1, 'H')));
assert_eq!(iter.next(), Some((1, 2, 1..2, 'e')));
assert_eq!(iter.next(), Some((1, 3, 2..3, 'l')));
assert_eq!(iter.next(), Some((1, 4, 3..4, 'l')));
assert_eq!(iter.next(), Some((1, 5, 4..5, 'o')));
assert_eq!(iter.next(), Some((1, 6, 5..6, ' ')));
assert_eq!(iter.next(), Some((1, 7, 6..10, 'šŸ‘‹')));
assert_eq!(iter.next(), Some((1, 8, 10..11, '\n')));
assert_eq!(iter.next(), Some((2, 1, 11..12, 'W')));
assert_eq!(iter.next(), Some((2, 2, 12..13, 'o')));
assert_eq!(iter.next(), Some((2, 3, 13..14, 'r')));
assert_eq!(iter.next(), Some((2, 4, 14..15, 'l')));
assert_eq!(iter.next(), Some((2, 5, 15..16, 'd')));
assert_eq!(iter.next(), Some((2, 6, 16..17, ' ')));
assert_eq!(iter.next(), Some((2, 7, 17..21, 'šŸŒ')));
assert_eq!(iter.next(), Some((2, 8, 21..22, '\n')));
assert_eq!(iter.next(), Some((3, 1, 22..26, 'šŸ¦€')));
assert_eq!(iter.next(), Some((3, 2, 26..30, 'šŸ¦€')));
assert_eq!(iter.next(), None);
Commit count: 0

cargo fmt