Compile an inclusive integer range [min, max] into the smallest practical
regex source string. The output matches exactly the decimal form of every
integer in the range.
The function returns a source string. Wrap it in ^...$ and hand it to your
regex engine.
[dependencies]
regex-range = "0.1"use regex_range::{to_regex_range, Options};
let opts = Options::default();
assert_eq!(to_regex_range("1", Some("5"), &opts).unwrap(), "[1-5]");
assert_eq!(
to_regex_range("10", Some("50"), &opts).unwrap(),
"(?:1[0-9]|[2-4][0-9]|50)"
);
assert_eq!(
to_regex_range("-10", Some("10"), &opts).unwrap(),
"(?:-[1-9]|-?10|[0-9])"
);A single argument, or max equal to min, returns the value verbatim:
# use regex_range::{to_regex_range, Options};
assert_eq!(to_regex_range("5", None, &Options::default()).unwrap(), "5");When min is greater than max, the bounds swap:
# use regex_range::{to_regex_range, Options};
assert_eq!(
to_regex_range("55", Some("10"), &Options::default()).unwrap(),
"(?:1[0-9]|[2-4][0-9]|5[0-5])"
);Inputs are decimal integer strings. A leading - and leading zeros are allowed.
Surrounding whitespace is trimmed. Blank strings, non-numeric strings, values
outside i64, and i64::MIN are rejected with an [Error]. Values up to
fifteen digits are covered by the test suite.
| Option | Default | Effect |
|---|---|---|
relax_zeros |
on | Make leading zeros optional in padded output (0?, 0{0,2}). Set to false for mandatory zeros (0, 00). |
strict_zeros |
unset | Inverse alias of relax_zeros. true turns relaxing off. |
shorthand |
off | Emit a scoped digit shorthand instead of [0-9] for full-digit positions. |
capture |
off | Wrap the whole result in a capturing group (...). Wraps even a single alternative. Takes precedence over wrap. |
wrap |
on | Wrap a multi-alternative result in a non-capturing group (?:...). Set to false to suppress it. |
use regex_range::{to_regex_range, Options};
// Optional leading zeros (default).
let src = to_regex_range("001", Some("100"), &Options::default()).unwrap();
assert_eq!(src, "(?:0{0,2}[1-9]|0?[1-9][0-9]|100)");
// Mandatory leading zeros.
let strict = Options::default().relax_zeros(false);
assert_eq!(to_regex_range("001", Some("005"), &strict).unwrap(), "00[1-5]");
// Shorthand digit class.
let short = Options::default().shorthand(true);
assert_eq!(
to_regex_range("0", Some("999999"), &short).unwrap(),
"(?:(?-u:\\d)|[1-9](?-u:\\d){1,5})"
);A zero-padded bound makes the range padded. The generated pattern then allows
leading zeros up to the width of max. Padding is detected as an optional sign,
a leading 0, then at least one more digit. The trailing digit may itself be
0, so "00" is padded. A lone "0" is not padded.
# use regex_range::{to_regex_range, Options};
let opts = Options::default();
assert_eq!(to_regex_range("01", Some("05"), &opts).unwrap(), "0?[1-5]");
assert_eq!(to_regex_range("0", Some("00"), &opts).unwrap(), "0?0");
assert_eq!(to_regex_range("0", Some("9"), &opts).unwrap(), "[0-9]");The output uses only these constructs, all accepted by the Rust regex crate:
- Character classes
[a-b]and[ab], and the digit class[0-9]or(?-u:\d). - Alternation
|. - Quantifiers
{n},{n,m}, and?. - Groups
(?:...)and(...). - A literal
-or optional-?sign. - Scoped flags
(?-u:...)whenshorthandis on.
Results are memoized in a process-wide cache. [clear_cache] empties it.
Licensed under the MIT license.