You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
128 lines
2.5 KiB
128 lines
2.5 KiB
//! PCRE
|
|
use super::*;
|
|
use pcre::{
|
|
Pcre,
|
|
};
|
|
use std::{
|
|
sync::{
|
|
Mutex,
|
|
},
|
|
error,
|
|
fmt,
|
|
};
|
|
|
|
#[derive(Debug)]
|
|
pub struct Regex(Mutex<Pcre>, String);
|
|
|
|
/// A regex error
|
|
#[derive(Debug)]
|
|
pub struct Error(pcre::CompilationError);
|
|
|
|
impl error::Error for Error{}
|
|
|
|
impl fmt::Display for Error
|
|
{
|
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result
|
|
{
|
|
write!(f,"regex failed to compile: ")?;
|
|
self.0.fmt(f)
|
|
}
|
|
}
|
|
|
|
impl From<pcre::CompilationError> for Error
|
|
{
|
|
#[inline] fn from(from: pcre::CompilationError) -> Self
|
|
{
|
|
Self(from)
|
|
}
|
|
}
|
|
|
|
pub struct Iter<'a>(Option<pcre::Match<'a>>, usize);
|
|
|
|
impl<'a> Iterator for Iter<'a>
|
|
{
|
|
type Item = &'a str;
|
|
fn next(&mut self) -> Option<Self::Item> {
|
|
if let Some(m) = &mut self.0 {
|
|
if self.1 >= m.string_count() {
|
|
None
|
|
} else {
|
|
let string = m.group(self.1);
|
|
self.1 +=1;
|
|
Some(string)
|
|
}
|
|
} else {
|
|
None
|
|
}
|
|
}
|
|
|
|
#[inline] fn size_hint(&self) -> (usize, Option<usize>) {
|
|
(self.len(), Some(self.len()))
|
|
}
|
|
}
|
|
|
|
impl<'a> std::iter::FusedIterator for Iter<'a>{}
|
|
impl<'a> ExactSizeIterator for Iter<'a>
|
|
{
|
|
fn len(&self) -> usize
|
|
{
|
|
match &self.0 {
|
|
Some(m) => m.string_count(),
|
|
None => 0,
|
|
}
|
|
}
|
|
}
|
|
|
|
impl Regex
|
|
{
|
|
/// Create a new regular expression from a string
|
|
pub fn new<I>(from: impl AsRef<str>, opt: I) -> Result<Self, Error>
|
|
where I: IntoIterator<Item=pcre::CompileOption>
|
|
{
|
|
let string = from.as_ref();
|
|
Ok(Self(Mutex::new(Pcre::compile_with_options(string, &opt.into_iter().collect())?), string.to_owned()))
|
|
}
|
|
|
|
/// Test against string
|
|
pub fn test(&self, string: impl AsRef<str>) -> bool
|
|
{
|
|
let mut regex = self.0.lock().unwrap();
|
|
regex.exec(string.as_ref()).is_some()
|
|
}
|
|
|
|
/// Get the groups of a match against string
|
|
pub fn exec_ref<'a>(&mut self, string: &'a (impl AsRef<str> + ?Sized)) -> Iter<'a>
|
|
{
|
|
let regex = self.0.get_mut().unwrap();
|
|
Iter(regex.exec(string.as_ref()), 0)
|
|
}
|
|
|
|
/// Get the groups as an owned string vector from map against string
|
|
pub fn exec(&self, string: impl AsRef<str>) -> Vec<String>
|
|
{
|
|
let mut regex = self.0.lock().unwrap();
|
|
Iter(regex.exec(string.as_ref()), 0).map(std::borrow::ToOwned::to_owned).collect()
|
|
}
|
|
|
|
/// Get the string used to create this regex
|
|
#[inline] pub fn as_str(&self) -> &str{
|
|
&self.1[..]
|
|
}
|
|
}
|
|
|
|
impl From<Regex> for Pcre
|
|
{
|
|
#[inline] fn from(from: Regex) -> Self
|
|
{
|
|
from.0.into_inner().unwrap()
|
|
}
|
|
}
|
|
|
|
impl fmt::Display for Regex
|
|
{
|
|
#[inline] fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result
|
|
{
|
|
write!(f, "{}", self.1)
|
|
}
|
|
}
|