descape

Crates.iodescape
lib.rsdescape
version2.0.3
sourcesrc
created_at2024-02-26 18:59:37.892957
updated_at2024-09-23 23:53:39.919538
descriptionAdds a single extension trait for &str to unescape any backslashes.
homepage
repositoryhttps://github.com/balt-dev/descape
max_upload_size
id1154030
size37,775
Balt (balt-dev)

documentation

README

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");
Commit count: 35

cargo fmt