1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132
|
[](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!"
)
```
|