Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 


Quelle  regex_set.rs   Sprache: unbekannt

 
//! A type that represents the union of a set of regular expressions.
#![deny(clippy::missing_docs_in_private_items)]

use regex::RegexSet as RxSet;
use std::cell::Cell;

/// A dynamic set of regular expressions.
#[derive(Clone, Debug, Default)]
pub struct RegexSet {
    items: Vec<Box<str>>,
    /// Whether any of the items in the set was ever matched. The length of this
    /// vector is exactly the length of `items`.
    matched: Vec<Cell<bool>>,
    set: Option<RxSet>,
    /// Whether we should record matching items in the `matched` vector or not.
    record_matches: bool,
}

impl RegexSet {
    /// Create a new RegexSet
    pub fn new() -> RegexSet {
        RegexSet::default()
    }

    /// Is this set empty?
    pub fn is_empty(&self) -> bool {
        self.items.is_empty()
    }

    /// Insert a new regex into this set.
    pub fn insert<S>(&mut self, string: S)
    where
        S: AsRef<str>,
    {
        self.items.push(string.as_ref().to_owned().into_boxed_str());
        self.matched.push(Cell::new(false));
        self.set = None;
    }

    /// Returns slice of String from its field 'items'
    pub fn get_items(&self) -> &[Box<str>] {
        &self.items
    }

    /// Returns an iterator over regexes in the set which didn't match any
    /// strings yet.
    pub fn unmatched_items(&self) -> impl Iterator<Item = &str> {
        self.items.iter().enumerate().filter_map(move |(i, item)| {
            if !self.record_matches || self.matched[i].get() {
                return None;
            }

            Some(item.as_ref())
        })
    }

    /// Construct a RegexSet from the set of entries we've accumulated.
    ///
    /// Must be called before calling `matches()`, or it will always return
    /// false.
    #[inline]
    pub fn build(&mut self, record_matches: bool) {
        self.build_inner(record_matches, None)
    }

    #[cfg(all(feature = "__cli", feature = "experimental"))]
    /// Construct a RegexSet from the set of entries we've accumulated and emit diagnostics if the
    /// name of the regex set is passed to it.
    ///
    /// Must be called before calling `matches()`, or it will always return
    /// false.
    #[inline]
    pub fn build_with_diagnostics(
        &mut self,
        record_matches: bool,
        name: Option<&'static str>,
    ) {
        self.build_inner(record_matches, name)
    }

    #[cfg(all(not(feature = "__cli"), feature = "experimental"))]
    /// Construct a RegexSet from the set of entries we've accumulated and emit diagnostics if the
    /// name of the regex set is passed to it.
    ///
    /// Must be called before calling `matches()`, or it will always return
    /// false.
    #[inline]
    pub(crate) fn build_with_diagnostics(
        &mut self,
        record_matches: bool,
        name: Option<&'static str>,
    ) {
        self.build_inner(record_matches, name)
    }

    fn build_inner(
        &mut self,
        record_matches: bool,
        _name: Option<&'static str>,
    ) {
        let items = self.items.iter().map(|item| format!("^({})$", item));
        self.record_matches = record_matches;
        self.set = match RxSet::new(items) {
            Ok(x) => Some(x),
            Err(e) => {
                warn!("Invalid regex in {:?}: {:?}", self.items, e);
                #[cfg(feature = "experimental")]
                if let Some(name) = _name {
                    invalid_regex_warning(self, e, name);
                }
                None
            }
        }
    }

    /// Does the given `string` match any of the regexes in this set?
    pub fn matches<S>(&self, string: S) -> bool
    where
        S: AsRef<str>,
    {
        let s = string.as_ref();
        let set = match self.set {
            Some(ref set) => set,
            None => return false,
        };

        if !self.record_matches {
            return set.is_match(s);
        }

        let matches = set.matches(s);
        if !matches.matched_any() {
            return false;
        }
        for i in matches.iter() {
            self.matched[i].set(true);
        }

        true
    }
}

#[cfg(feature = "experimental")]
fn invalid_regex_warning(
    set: &RegexSet,
    err: regex::Error,
    name: &'static str,
) {
    use crate::diagnostics::{Diagnostic, Level, Slice};

    let mut diagnostic = Diagnostic::default();

    match err {
        regex::Error::Syntax(string) => {
            if string.starts_with("regex parse error:\n") {
                let mut source = String::new();

                let mut parsing_source = true;

                for line in string.lines().skip(1) {
                    if parsing_source {
                        if line.starts_with(' ') {
                            source.push_str(line);
                            source.push('\n');
                            continue;
                        }
                        parsing_source = false;
                    }
                    let error = "error: ";
                    if line.starts_with(error) {
                        let (_, msg) = line.split_at(error.len());
                        diagnostic.add_annotation(msg.to_owned(), Level::Error);
                    } else {
                        diagnostic.add_annotation(line.to_owned(), Level::Info);
                    }
                }
                let mut slice = Slice::default();
                slice.with_source(source);
                diagnostic.add_slice(slice);

                diagnostic.with_title(
                    "Error while parsing a regular expression.",
                    Level::Warn,
                );
            } else {
                diagnostic.with_title(string, Level::Warn);
            }
        }
        err => {
            let err = err.to_string();
            diagnostic.with_title(err, Level::Warn);
        }
    }

    diagnostic.add_annotation(
        format!("This regular expression was passed via `{}`.", name),
        Level::Note,
    );

    if set.items.iter().any(|item| item.as_ref() == "*") {
        diagnostic.add_annotation("Wildcard patterns \"*\" are no longer considered valid. Use \".*\" instead.", Level::Help);
    }
    diagnostic.display();
}

[ Dauer der Verarbeitung: 0.21 Sekunden  (vorverarbeitet)  ]

                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Software

     Produkte
     Quellcodebibliothek

Aktivitäten

     Artikel über Sicherheit
     Anleitung zur Aktivierung von SSL

Muße

     Gedichte
     Musik
     Bilder

Jenseits des Üblichen ....
    

Besucherstatistik

Besucherstatistik

Monitoring

Montastic status badge