Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
### next
- `regex_if!` and `bytes_regex_if!`
- `regex_switch!` and `bytes_regex_switch!`

<a name="v3.1.0"></a>
### v3.1.0 - 2023-11-09
- bytes_ prefixed macros create instances of `bytes::Regex` - Fix #30
Expand Down
32 changes: 29 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,10 +31,11 @@ Other macros are specialized for testing a match, replacing with concise closure
* `regex_captures!`
* `regex_replace!`
* `regex_replace_all!`
* `regex_switch!`

They support the `B` flag for the `regex::bytes::Regex` variant.

All macros exist with a `bytes_` prefix for building `bytes::Regex`, so you also have `bytes_regex!`, `bytes_regex_is_match!`, `bytes_regex_find!`, `bytes_regex_captures!`, `bytes_regex_replace!`, and `bytes_regex_replace_all!`.
All macros exist with a `bytes_` prefix for building `bytes::Regex`, so you also have `bytes_regex!`, `bytes_regex_is_match!`, `bytes_regex_find!`, `bytes_regex_captures!`, `bytes_regex_replace!`, `bytes_regex_replace_all!`, and `bytes_regex_switch!`.

Some structs of the regex crate are reexported to ease dependency managment.
The regex crate itself is also reexported, to avoid the need to synchronize the versions/flavor (see [Features](#features_and_reexport) below)
Expand Down Expand Up @@ -130,7 +131,7 @@ You receive `""` for optional groups with no value.

The [regex_replace!] and [regex_replace_all!] macros bring once compilation and compilation time checks to the `replace` and `replace_all` functions.

## Replacing with a closure
## Replace with a closure

```rust
use lazy_regex::regex_replace_all;
Expand All @@ -147,7 +148,7 @@ The number of arguments given to the closure is checked at compilation time to m

If it doesn't match you get, at compilation time, a clear error message.

## Replacing with another kind of Replacer
## Replace with another kind of Replacer

```rust
use lazy_regex::regex_replace_all;
Expand All @@ -156,6 +157,31 @@ let output = regex_replace_all!("U", text, "O");
assert_eq!(&output, "OwO");
```

# Switch over regexes

Execute the expression bound to the first matching regex, with named captured groups declared as varibles:

```rust
use lazy_regex::regex_switch;
pub enum ScrollCommand {
Top,
Bottom,
Lines(i32),
Pages(i32),
}
impl std::str::FromStr for ScrollCommand {
type Err = ();
fn from_str(s: &str) -> Result<Self, ()> {
regex_switch!(s,
"^scroll-to-top$" => Self::Top,
"^scroll-to-bottom$" => Self::Bottom,
r#"^scroll-lines?\((?<n>[+-]?\d{1,4})\)$"# => Self::Lines(n.parse().unwrap()),
r#"^scroll-pages?\((?<n>[+-]?\d{1,4})\)$"# => Self::Pages(n.parse().unwrap()),
).ok_or(())
}
}
```

# Shared lazy static

When a regular expression is used in several functions, you sometimes don't want
Expand Down
37 changes: 34 additions & 3 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,11 @@ But most often, you won't even use the `regex!` macro but the other macros which
* [regex_captures!]
* [regex_replace!]
* [regex_replace_all!]
* [regex_switch!]

They support the `B` flag for the `regex::bytes::Regex` variant.

All macros exist with a `bytes_` prefix for building `bytes::Regex`, so you also have [bytes_regex!], [bytes_regex_is_match!], [bytes_regex_find!], [bytes_regex_captures!], [bytes_regex_replace!], and [bytes_regex_replace_all!].
All macros exist with a `bytes_` prefix for building `bytes::Regex`, so you also have [bytes_regex!], [bytes_regex_is_match!], [bytes_regex_find!], [bytes_regex_captures!], [bytes_regex_replace!], [bytes_regex_replace_all!], and [bytes_regex_switch!].

Some structs of the regex crate are reexported to ease dependency managment.

Expand Down Expand Up @@ -129,7 +130,7 @@ doc: [regex_captures!]

The [regex_replace!] and [regex_replace_all!] macros bring once compilation and compilation time checks to the `replace` and `replace_all` functions.

## Replacing with a closure
## Replace with a closure

```rust
use lazy_regex::regex_replace_all;
Expand All @@ -146,7 +147,7 @@ The number of arguments given to the closure is checked at compilation time to m

If it doesn't match you get, at compilation time, a clear error message.

## Replacing with another kind of Replacer
## Replace with another kind of Replacer

```rust
use lazy_regex::regex_replace_all;
Expand All @@ -155,6 +156,32 @@ let output = regex_replace_all!("U", text, "O");
assert_eq!(&output, "OwO");
```

# Switch over regexes

Execute the expression bound to the first matching regex, with named captured groups declared as varibles:

```rust
use lazy_regex::regex_switch;
pub enum ScrollCommand {
Top,
Bottom,
Lines(i32),
Pages(i32),
}
impl std::str::FromStr for ScrollCommand {
type Err = ();
fn from_str(s: &str) -> Result<Self, ()> {
regex_switch!(s,
"^scroll-to-top$" => Self::Top,
"^scroll-to-bottom$" => Self::Bottom,
r#"^scroll-lines?\((?<n>[+-]?\d{1,4})\)$"# => Self::Lines(n.parse().unwrap()),
r#"^scroll-pages?\((?<n>[+-]?\d{1,4})\)$"# => Self::Pages(n.parse().unwrap()),
).ok_or(())
}
}
```

doc: [regex_switch!]

# Shared lazy static

Expand Down Expand Up @@ -187,16 +214,20 @@ pub use {
regex,
regex_captures,
regex_find,
regex_if,
regex_is_match,
regex_replace,
regex_replace_all,
regex_switch,
bytes_lazy_regex,
bytes_regex,
bytes_regex_captures,
bytes_regex_find,
bytes_regex_if,
bytes_regex_is_match,
bytes_regex_replace,
bytes_regex_replace_all,
bytes_regex_switch,
},
once_cell::sync::Lazy,
};
Expand Down
76 changes: 74 additions & 2 deletions src/proc_macros/args.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,13 @@
use syn::{
parse::{Parse, ParseStream, Result},
Expr, ExprClosure, LitStr, Token,
parse::{
Parse,
ParseStream,
Result,
},
Expr,
ExprClosure,
LitStr,
Token,
};

/// Wrapping of the two arguments given to one of the
Expand Down Expand Up @@ -56,3 +63,68 @@ impl Parse for ReplaceArgs {
}
}

/// Wrapping of the arguments given to a regex_if macro
pub(crate) struct RexIfArgs {
pub regex_str: LitStr,
pub value: Expr, // this expression is (or produces) the text to search or check
pub then: Expr,
}

impl Parse for RexIfArgs {
fn parse(input: ParseStream<'_>) -> Result<Self> {
let regex_str = input.parse::<LitStr>()?;
input.parse::<Token![,]>()?;
let value = input.parse::<Expr>()?;
input.parse::<Token![,]>()?;
let then = input.parse::<Expr>()?;
let _ = input.parse::<Token![,]>(); // allow a trailing comma
Ok(Self {
regex_str,
value,
then,
})
}
}

/// Wrapping of the arguments given to a regex_switch macro
pub(crate) struct RexSwitchArgs {
pub value: Expr, // this expression is (or produces) the text to search or check
pub arms: Vec<RexSwitchArmArgs>,
}
pub(crate) struct RexSwitchArmArgs {
pub regex_str: LitStr,
pub then: Expr,
}

impl Parse for RexSwitchArgs {
fn parse(input: ParseStream<'_>) -> Result<Self> {
let value = input.parse::<Expr>()?;
input.parse::<Token![,]>()?;
let mut arms = Vec::new();
loop {
let lookahead = input.lookahead1();
if lookahead.peek(LitStr) {
let arm = input.parse::<RexSwitchArmArgs>()?;
arms.push(arm);
} else {
break;
}
}
Ok(Self {
value,
arms,
})
}
}
impl Parse for RexSwitchArmArgs {
fn parse(input: ParseStream<'_>) -> Result<Self> {
let regex_str = input.parse::<LitStr>()?;
input.parse::<Token![=>]>()?;
let then = input.parse::<Expr>()?;
let _ = input.parse::<Token![,]>(); // allow a trailing comma
Ok(Self {
regex_str,
then,
})
}
}
Loading