gpt4 book ai didi

regex - 如何编写两个对 Regex::replace_all 的调用?

转载 作者:行者123 更新时间:2023-12-05 00:42:45 25 4
gpt4 key购买 nike

Regex::replace_all 有签名fn (text: &str) -> Cow<str> .对此的两次调用将如何编写,f(g(x)) ,给出相同的签名?

这是我正在尝试编写的一些代码。这将两个调用分成两个函数,但我也无法让它在一个函数中工作。这是我的lib.rs在一个新的 Cargo 项目中:

#![allow(dead_code)]

/// Plaintext and HTML manipulation.

use lazy_static::lazy_static;
use regex::Regex;
use std::borrow::Cow;

lazy_static! {
static ref DOUBLE_QUOTED_TEXT: Regex = Regex::new(r#""(?P<content>[^"]+)""#).unwrap();
static ref SINGLE_QUOTE: Regex = Regex::new(r"'").unwrap();
}


fn add_typography(text: &str) -> Cow<str> {
add_double_quotes(&add_single_quotes(text)) // Error! "returns a value referencing data owned by the current function"
}

fn add_double_quotes(text: &str) -> Cow<str> {
DOUBLE_QUOTED_TEXT.replace_all(text, "“$content”")
}

fn add_single_quotes(text: &str) -> Cow<str> {
SINGLE_QUOTE.replace_all(text, "’")
}


#[cfg(test)]
mod tests {
use crate::{add_typography};

#[test]
fn converts_to_double_quotes() {
assert_eq!(add_typography(r#""Hello""#), "“Hello”");
}

#[test]
fn converts_a_single_quote() {
assert_eq!(add_typography("Today's Menu"), "Today’s Menu");
}
}

这是我能想到的最好的方法,但是在组合三个或四个函数时这会很快变得难看:

fn add_typography(input: &str) -> Cow<str> {
match add_single_quotes(input) {
Cow::Owned(output) => add_double_quotes(&output).into_owned().into(),
_ => add_double_quotes(input),
}
}

最佳答案

Cow 包含 可能拥有 数据。

我们可以从 replace_all 函数的作用推断,它仅在没有发生替换时才返回借用的数据,否则它必须返回新的、拥有的数据。

当内部调用进行替换而外部调用没有进行替换时,就会出现问题。在这种情况下,外部调用将简单地将其输入作为 Cow::Borrowed 传递,但它从内部调用返回的 Cow::Owned 值中借用,其data 现在属于 add_typography() 本地的 Cow 临时文件。因此,该函数将返回一个 Cow::Borrowed,但会从临时对象中借用,这显然不是内存安全的。

基本上,此函数只会在任一调用均未进行替换时返回借用的数据。我们需要的是一个帮助器,只要返回的 Cow 本身是拥有的,它就可以通过调用层传播所有权。

我们可以在 Cow 之上构造一个 .map() 扩展方法,它正是这样做的:

use std::borrow::{Borrow, Cow};

trait CowMapExt<'a, B>
where B: 'a + ToOwned + ?Sized
{
fn map<F>(self, f: F) -> Self
where F: for <'b> FnOnce(&'b B) -> Cow<'b, B>;
}

impl<'a, B> CowMapExt<'a, B> for Cow<'a, B>
where B: 'a + ToOwned + ?Sized
{
fn map<F>(self, f: F) -> Self
where F: for <'b> FnOnce(&'b B) -> Cow<'b, B>
{
match self {
Cow::Borrowed(v) => f(v),
Cow::Owned(v) => Cow::Owned(f(v.borrow()).into_owned()),
}
}
}

现在您的调用站点可以保持整洁:

fn add_typography(text: &str) -> Cow<str> {
add_single_quotes(text).map(add_double_quotes)
}

关于regex - 如何编写两个对 Regex::replace_all 的调用?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/72179485/

25 4 0
文章推荐: c++ - 为什么 not_null 还没有进入 C++ 标准?
文章推荐: c - 删除逗号之间的白色字符,但不删除逗号内的内容
文章推荐: java - 按当前月份排序 List 到最近六个月