File: README.md

package info (click to toggle)
rust-descape 3.0.0-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 152 kB
  • sloc: makefile: 4
file content (132 lines) | stat: -rw-r--r-- 4,401 bytes parent folder | download
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
[![GitHub Actions Workflow Status](https://img.shields.io/github/actions/workflow/status/balt-dev/descape/.github%2Fworkflows%2Frust.yml?branch=master&style=flat&label=tests)](https://github.com/balt-dev/descape/actions/)
[![Coverage](https://coveralls.io/repos/github/balt-dev/descape/badge.svg?branch=master)](https://coveralls.io/github/balt-dev/descape/)
[![Documentation](https://docs.rs/descape/badge.svg)](https://docs.rs/descape)
[![MSRV](https://img.shields.io/badge/MSRV-1.52.1-gold)](https://gist.github.com/alexheretic/d1e98d8433b602e57f5d0a9637927e0c)
[![Repository](https://img.shields.io/badge/-GitHub-%23181717?style=flat&logo=github&labelColor=%23555555&color=%23181717)](https://github.com/balt-dev/descape)
[![Latest version](https://img.shields.io/crates/v/descape.svg)](https://crates.io/crates/descape)
[![License](https://img.shields.io/crates/l/descape.svg)](https://github.com/balt-dev/descape/blob/master/LICENSE-MIT)
[![unsafe forbidden](https://img.shields.io/badge/unsafe-forbidden-success.svg)](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>&bsol;&bsol;&grave;</code> -> <code>&grave;</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!"
)
```