#escaping #string #string-parser #unicode #zero-copy

no-std descape

Adds a single extension trait for &str to unescape any backslashes

7 stable releases

2.0.3 Sep 23, 2024
1.2.0 Sep 14, 2024
1.1.3 Sep 13, 2024
1.1.2 Feb 27, 2024
1.0.1 Feb 26, 2024

#45 in Parser tooling

Download history 9/week @ 2024-08-17 9/week @ 2024-08-24 22/week @ 2024-08-31 163/week @ 2024-09-07 294/week @ 2024-09-14 628/week @ 2024-09-21 147/week @ 2024-09-28 45/week @ 2024-10-05 68/week @ 2024-10-12 53/week @ 2024-10-19 39/week @ 2024-10-26 112/week @ 2024-11-02 46/week @ 2024-11-09 20/week @ 2024-11-16 85/week @ 2024-11-23 77/week @ 2024-11-30

252 downloads per month
Used in 2 crates

Apache-2.0 OR MIT

20KB
187 lines

GitHub Actions Workflow Status Coverage Documentation MSRV Repository Latest version License unsafe forbidden

descape

Provides utilities for easily parsing escape sequences in a string, using alloc::borrow::Cow to only borrow when needed.

This library supports many escape sequences:

  • \\a -> \x07
  • \\b -> \x08
  • \\t -> \x09
  • \\n -> \x0A
  • \\v -> \x0B
  • \\f -> \x0C
  • \\r -> \x0D
  • \\e -> \x1B
  • \\' -> '
  • \\" -> "
  • \\` -> `
  • \\\\ -> \\
  • \\xNN -> \xNN
  • \\o -> \o, for all octal digits o
  • \\oo -> \oo, for all octal digits o
  • \\ooo -> \ooo, for all octal digits o
  • \\uXXXX -> \u{XXXX}
  • \\u{HEX} -> \u{HEX}

Along with this, you can define your own custom escape handlers! See UnescapeExt::to_unescaped_with for more information on that.

This crate supports no-std.

Optionally, this crate has the std and core_error features, to allow the error type of an invalid escape to implement the Error trait.

std uses std::error::Error, and core_error depends on core::error::Error, which is stable on Rust 1.82.0 or greater.

Examples

Parsing an escaped string

let escaped = "Hello,\\nworld!".to_unescaped();
assert_eq!(
    escaped.unwrap(),
    Cow::Owned::<'_, str>("Hello,\nworld!".to_string())
);

Not allocating for a string without escapes

let no_escapes = "No escapes here!".to_unescaped();
assert_eq!(
    no_escapes.unwrap(),
    Cow::Borrowed("No escapes here!")
);

Erroring for invalid escapes

//                            v  invalid at index 7
let invalid_escape = r"Uh oh! \xJJ".to_unescaped();
assert_eq!(
    invalid_escape.unwrap_err().index,
    7
);

Permitting any escape, handing it back raw

fn raw(idx: usize, chr: char, _: &mut CharIndices) -> Result<Option<char>, ()> {
    Ok(Some(chr))
}

let escaped = r"\H\e\l\l\o \n \W\o\r\l\d";
let unescaped = escaped.to_unescaped_with(raw).expect("this is fine");
assert_eq!(unescaped, "Hello n World");

Removing escape sequences entirely

fn raw(idx: usize, chr: char, _: &mut CharIndices) -> Result<Option<char>, ()> {
    Ok(None)
}

let escaped = r"What if I want a \nnewline?";
let unescaped = escaped.to_unescaped_with(raw).expect("this should work");
assert_eq!(unescaped, "What if I want a newline?");

Not allowing escape sequences unsupported by Rust

fn rust_only(idx: usize, chr: char, iter: &mut CharIndices) -> Result<Option<char>, ()> {
    match chr {
        'a' | 'b' | 'v' | 'f' | 'e' | '`' => Err(()),
        _ => descape::DefaultHandler.escape(idx, chr, iter)
    }
}

r"This is \nfine".to_unescaped_with(rust_only).expect(r"\n is valid");
r"This is not \fine".to_unescaped_with(rust_only).expect_err(r"\f is invalid");

No runtime deps

Features