{"id":16856420,"url":"https://github.com/vallentin/char-ranges","last_synced_at":"2025-10-17T15:21:29.784Z","repository":{"id":172451513,"uuid":"649323527","full_name":"vallentin/char-ranges","owner":"vallentin","description":null,"archived":false,"fork":false,"pushed_at":"2024-04-16T04:03:18.000Z","size":16,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-01-24T17:34:56.170Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/vallentin.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2023-06-04T13:52:47.000Z","updated_at":"2023-06-04T14:07:21.000Z","dependencies_parsed_at":"2025-01-24T17:39:49.148Z","dependency_job_id":null,"html_url":"https://github.com/vallentin/char-ranges","commit_stats":null,"previous_names":["vallentin/char-ranges"],"tags_count":1,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/vallentin%2Fchar-ranges","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/vallentin%2Fchar-ranges/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/vallentin%2Fchar-ranges/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/vallentin%2Fchar-ranges/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/vallentin","download_url":"https://codeload.github.com/vallentin/char-ranges/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":244207746,"owners_count":20416109,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-10-13T14:04:11.881Z","updated_at":"2025-10-17T15:21:24.750Z","avatar_url":"https://github.com/vallentin.png","language":"Rust","readme":"# char-ranges\n\n[![CI](https://github.com/vallentin/char-ranges/workflows/CI/badge.svg)](https://github.com/vallentin/char-ranges/actions?query=workflow%3ACI)\n[![Latest Version](https://img.shields.io/crates/v/char-ranges.svg)](https://crates.io/crates/char-ranges)\n[![Docs](https://docs.rs/char-ranges/badge.svg)](https://docs.rs/char-ranges)\n[![License](https://img.shields.io/github/license/vallentin/char-ranges.svg)](https://github.com/vallentin/char-ranges)\n\nSimilar to the standard library's [`.char_indicies()`], but instead of only\nproducing the start byte position. This library implements [`.char_ranges()`],\nthat produce both the start and end byte positions.\n\nNote that simply using [`.char_indicies()`] and creating a range by mapping the\nreturned index `i` to `i..(i + 1)` is not guaranteed to be valid. Given that\nsome UTF-8 characters can be up to 4 bytes.\n\n| Char  | Bytes | Range  |\n| :---: | :---: | :----: |\n| `'O'` |   1   | `0..1` |\n| `'Ø'` |   2   | `0..2` |\n| `'∈'` |   3   | `0..3` |\n| `'🌏'` |   4   | `0..4` |\n\n_Assumes encoded in UTF-8._\n\nThe implementation specializes [`last()`], [`nth()`], [`next_back()`],\nand [`nth_back()`]. Such that the length of intermediate characters is\nnot wastefully calculated.\n\n## Example\n\n```rust\nuse char_ranges::CharRangesExt;\n\nlet text = \"Hello 🗻∈🌏\";\n\nlet mut chars = text.char_ranges();\nassert_eq!(chars.as_str(), \"Hello 🗻∈🌏\");\n\nassert_eq!(chars.next(), Some((0..1, 'H'))); // These chars are 1 byte\nassert_eq!(chars.next(), Some((1..2, 'e')));\nassert_eq!(chars.next(), Some((2..3, 'l')));\nassert_eq!(chars.next(), Some((3..4, 'l')));\nassert_eq!(chars.next(), Some((4..5, 'o')));\nassert_eq!(chars.next(), Some((5..6, ' ')));\n\n// Get the remaining substring\nassert_eq!(chars.as_str(), \"🗻∈🌏\");\n\nassert_eq!(chars.next(), Some((6..10, '🗻'))); // This char is 4 bytes\nassert_eq!(chars.next(), Some((10..13, '∈'))); // This char is 3 bytes\nassert_eq!(chars.next(), Some((13..17, '🌏'))); // This char is 4 bytes\nassert_eq!(chars.next(), None);\n```\n\n## `DoubleEndedIterator`\n\n[`CharRanges`] also implements [`DoubleEndedIterator`] making it possible to iterate backwards.\n\n```rust\nuse char_ranges::CharRangesExt;\n\nlet text = \"ABCDE\";\n\nlet mut chars = text.char_ranges();\nassert_eq!(chars.as_str(), \"ABCDE\");\n\nassert_eq!(chars.next(), Some((0..1, 'A')));\nassert_eq!(chars.next_back(), Some((4..5, 'E')));\nassert_eq!(chars.as_str(), \"BCD\");\n\nassert_eq!(chars.next_back(), Some((3..4, 'D')));\nassert_eq!(chars.next(), Some((1..2, 'B')));\nassert_eq!(chars.as_str(), \"C\");\n\nassert_eq!(chars.next(), Some((2..3, 'C')));\nassert_eq!(chars.as_str(), \"\");\n\nassert_eq!(chars.next(), None);\n```\n\n## Offset Ranges\n\nIf the input `text` is a substring of some original text, and the produced\nranges are desired to be offset in relation to the substring. Then instead\nof [`.char_ranges()`] use \u003ccode\u003e[.char_ranges_offset]\\(offset)\u003c/code\u003e\nor \u003ccode\u003e.[char_ranges]\\().[offset]\\(offset)\u003c/code\u003e.\n\n```rust\nuse char_ranges::CharRangesExt;\n\nlet text = \"Hello 👋 World 🌏\";\n\nlet start = 11; // Start index of 'W'\nlet text = \u0026text[start..]; // \"World 🌏\"\n\nlet mut chars = text.char_ranges_offset(start);\n// or\n// let mut chars = text.char_ranges().offset(start);\n\nassert_eq!(chars.next(), Some((11..12, 'W'))); // These chars are 1 byte\nassert_eq!(chars.next(), Some((12..13, 'o')));\nassert_eq!(chars.next(), Some((13..14, 'r')));\n\nassert_eq!(chars.next_back(), Some((17..21, '🌏'))); // This char is 4 bytes\n```\n\n[`.char_ranges()`]: https://docs.rs/char-ranges/*/char_ranges/trait.CharRangesExt.html#tymethod.char_ranges\n[char_ranges]: https://docs.rs/char-ranges/*/char_ranges/trait.CharRangesExt.html#tymethod.char_ranges\n[char_ranges()]: https://docs.rs/char-ranges/*/char_ranges/trait.CharRangesExt.html#tymethod.char_ranges\n[.char_ranges_offset]: https://docs.rs/char-ranges/*/char_ranges/trait.CharRangesExt.html#tymethod.char_ranges_offset\n[offset]: https://docs.rs/char-ranges/0.1.0/char_ranges/struct.CharRanges.html#method.offset\n[`CharRanges`]: https://docs.rs/char-ranges/*/char_ranges/struct.CharRanges.html\n\n[`.char_indicies()`]: https://doc.rust-lang.org/std/primitive.str.html#method.char_indices\n[`DoubleEndedIterator`]: https://doc.rust-lang.org/std/iter/trait.DoubleEndedIterator.html\n\n[`last()`]: https://doc.rust-lang.org/std/iter/trait.Iterator.html#method.last\n[`nth()`]: https://doc.rust-lang.org/std/iter/trait.Iterator.html#method.nth\n[`next_back()`]: https://doc.rust-lang.org/std/iter/trait.DoubleEndedIterator.html#tymethod.next_back\n[`nth_back()`]: https://doc.rust-lang.org/std/iter/trait.DoubleEndedIterator.html#method.nth_back\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fvallentin%2Fchar-ranges","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fvallentin%2Fchar-ranges","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fvallentin%2Fchar-ranges/lists"}