简体   繁体   English

在 rust 中获取与 `Pattern` 匹配的 &str 的前缀切片

[英]Take prefix slice of &str that matches `Pattern` in rust

My ultimate goal is to parse the prefix number of a &str if there is one.我的最终目标是解析&str的前缀号(如果有的话)。 So I want a function that given "123abc345" will give me a pair (u32, &str) which is (123, "abc345") .所以我想要一个 function 给定"123abc345"会给我一对(u32, &str)这是(123, "abc345")

My idea is that if I have a Pattern type I should be able to do something like我的想法是,如果我有一个Pattern类型,我应该能够做类似的事情

/// `None` if there is no prefix in `s` that matches `p`,
/// Otherwise a pair of the longest matching prefix and the rest
/// of the string `s`.
fn split_prefix<P:Pattern<'a>(s: &'a str, p: P) -> Option<(&'a str, &'a str)>;

My goal would be achieved by doing something like我的目标将通过做类似的事情来实现

let num = if let Some((num_s, rest)) = split_prefix(s, char::is_digit) {
  s = rest;
  num_s.parse()
}

What's the best way to get that?获得它的最佳方法是什么?

I looked at the source for str::split_once and modified slightly to inclusively return a greedily matched prefix.我查看了str::split_once的源代码并稍作修改以包含返回一个贪婪匹配的前缀。

Playground 操场

#![feature(pattern)]
use std::str::pattern::{Pattern, Searcher};

/// See source code for `std::str::split_once`
fn split_prefix<'a, P: Pattern<'a>>(s: &'a str, p: P) -> Option<(&'a str, &'a str)> {
    let (start, _) = p.into_searcher(s).next_reject()?;
    // `start` here is the start of the unmatched (rejected) substring, so that is our sole delimiting index
    unsafe { Some((s.get_unchecked(..start), s.get_unchecked(start..))) }                                    

    // If constrained to strictly safe rust code, an alternative is:
    // s.get(..start).zip(s.get(start..))
}

This generic prefix splitter could then be wrapped in a specialized function to parse out numerical prefixes:然后可以将此通用前缀拆分器包装在专用的 function 中以解析数字前缀:

fn parse_numeric_prefix<'a>(s: &'a str) -> Option<(u32, &'a str)> {                                             
    split_prefix(s, char::is_numeric)
        .map(|(num_s, rest)| num_s.parse().ok().zip(Some(rest)))
        .flatten()
}

UPDATE: I just re-read your question and realized you want a None when there is no prefix match.更新:我刚刚重新阅读了你的问题并意识到当没有前缀匹配时你想要一个None Updated functions:更新功能:

Playground 操场

fn split_prefix<'a, P: Pattern<'a>>(s: &'a str, p: P) -> Option<(&'a str, &'a str)> {
    let (start, _) = p.into_searcher(s).next_reject()?;
    if start == 0 {
        None
    } else {
        unsafe { Some((s.get_unchecked(..start), s.get_unchecked(start..))) }
    }
}

fn parse_numeric_prefix<'a>(s: &'a str) -> Option<(u32, &'a str)> {                                             
    split_prefix(s, char::is_numeric)
        // We can unwrap the bare `Result` now since we know there's a
        // matched numeric which will parse
        .map(|(num_s, rest)| (num_s.parse().unwrap(), rest))
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM