[](https://github.com/balt-dev/descape/actions/)
[](https://coveralls.io/github/balt-dev/descape/)
[](https://docs.rs/descape)
[](https://gist.github.com/alexheretic/d1e98d8433b602e57f5d0a9637927e0c)
[](https://github.com/balt-dev/descape)
[](https://crates.io/crates/descape)
[](https://github.com/balt-dev/descape/blob/master/LICENSE-MIT)
[](https://github.com/rust-secure-code/safety-dance/)
# 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`
- `\\'` -> `'`
- `\\"` -> `"`
- <code>\\`</code> -> <code>`</code>
- `\\\\` -> `\\`
- `\\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!
Custom escape handlers support multi-character escape results,
skipping past escape sequences,
and even custom escape prefixes!
See `descape::EscapeHandler`.
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
```rust
let escaped = "Hello,\\nworld!".to_unescaped();
assert_eq!(
escaped.unwrap(),
Cow::Owned::<'_, str>("Hello,\nworld!".to_string())
);
```
### Not allocating for a string without escapes
```rust
let no_escapes = "No escapes here!".to_unescaped();
assert_eq!(
no_escapes.unwrap(),
Cow::Borrowed("No escapes here!")
);
```
### Erroring for invalid escapes
```rust
// 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
```rust
fn raw(idx: usize, chr: char, _: &mut CharIndices) -> Result<EscapeValue<'_>, ()> {
Ok(chr.into())
}
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
```rust
fn raw(idx: usize, chr: char, _: &mut CharIndices) -> Result<EscapeValue<'_>, ()> {
Ok(EscapeValue::Remove)
}
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
```rust
fn rust_only(idx: usize, chr: char, iter: &mut CharIndices) -> Result<EscapeValue<'_>, ()> {
match chr {
'a' | 'b' | 'v' | 'f' | 'e' | '`' => Err(()),
_ => descape::DefaultEscapeHandler.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");
```
## Custom escape prefixes
```rust
struct PercentEscape;
impl EscapeHandler for PercentEscape {
fn prefix(&self) -> char { '%' };
fn escape<'iter, 'source>(&mut self, idx: usize, chr: char, iter: &'iter mut CharIndices<'source>) -> Result<EscapeValue<'source>, ()> {
descape::DefaultEscapeHandler.escape(idx, chr, iter)
}
}
assert_eq!(
r"Hello,%tworld!".to_unescaped_with(PercentEscape).unwrap(),
"Hello,\tworld!"
)
```