html - 编写 HTML 解析器时借用的值不够长

标签 html regex pointers rust

我是 Rust 的新手,正在尝试构建 HTML 解析器。 我首先尝试解析字符串并将其放入 Hashmap<&str, i32> . 我发现我必须处理信件的情况。 所以我添加了 tag.to_lowercase()这会创建一个 String类型。从那里它让我的大脑 panic 。

下面是我的代码片段。

fn html_parser<'a>(html:&'a str, mut tags:HashMap<&'a str, i32>) -> HashMap<&'a str, i32>{

    let re = Regex::new("<[:alpha:]+?[\\d]*[:space:]*>+").unwrap();
    let mut count;
    for caps in re.captures_iter(html) {        
        if !caps.at(0).is_none(){
            let tag = &*(caps.at(0).unwrap().trim_matches('<').trim_matches('>').to_lowercase());
            count = 1;

            if tags.contains_key(tag){
                count = *tags.get_mut(tag).unwrap() + 1;
            }
            tags.insert(tag,count);
        }       
    }    
    tags
}

抛出这个错误,

src\main.rs:58:27: 58:97 error: borrowed value does not live long enough
src\main.rs:58 let tag:&'a str = &*(caps.at(0).unwrap().trim_matches('<').trim_matches('>').to_lowercase());
                                                         ^~~~~~~~~~~~~~~~~~~
src\main.rs:49:90: 80:2 note: reference must be valid for the lifetime 'a as defined on the block at 49:89...
src\main.rs:49 fn html_parser<'a>(html:&'a str, mut tags:HashMap<&'a str, i32>)-> HashMap<&'a str, i32>{
src\main.rs:58:99: 68:6 note: ...but borrowed value is only valid for the block suffix following statement 0 at 58:98
src\main.rs:58 let tag:&'a str = &*(caps.at(0).unwrap().trim_matches('<').trim_matches('>').to_lowercase());
src\main.rs:63
           ...
error: aborting due to previous error

我读过 Rust 中的生命周期,但仍然无法理解这种情况。

如果谁有好的 HTML 标签正则表达式,请推荐,以便我使用。

最佳答案

要了解您的问题,查看函数签名很有用:

fn html_parser<'a>(html: &'a str, mut tags: HashMap<&'a str, i32>) -> HashMap<&'a str, i32>

从这个签名中我们可以粗略地看出,接受和返回的 HashMap 都可能仅由 html 的子片作为键控。 .但是,在您的代码中,您试图插入一个与 html 完全无关(在生命周期意义上)的字符串切片。 :

let tag = &*(caps.at(0).unwrap().trim_matches('<').trim_matches('>').to_lowercase());

这里的第一个问题(你的特定错误正是关于这个问题)是你试图从临时 String 中取出一个切片由 to_lowercase() 返回.这个临时字符串只在这个语句期间有效,所以当语句结束时,字符串被释放,如果编译器不禁止,它的引用将变为悬空。所以,这个作业的正确写法如下:

let tag = caps.at(0).unwrap().trim_matches('<').trim_matches('>').to_lowercase();
let tag = &*tag;

(或者你可以直接使用top tag,用的时候转成slice)

但是,即使经过此更改,您的代码也无法正常工作。 to_lowercase()方法分配一个新的 String这与 html 无关在生命周期方面。因此,您从中取出的任何切片的生命周期必然短于 'a .因此不可能将这样的切片作为键插入到映射中,因为它们指向的数据在该函数返回后可能无效(并且在这种特殊情况下,它无效)。

很难说解决此问题的最佳方法是什么,因为它可能取决于程序的整体架构,但最简单的方法是创建一个新的 HashMap<String, i32>函数内部:

fn html_parser(html:&str, tags: HashMap<&str, i32>) -> HashMap<String, i32>{
    let mut result: HashMap<String, i32> = tags.iter().map(|(k, v)| (k.to_owned(), *v)).collect();
    let re = Regex::new("<[:alpha:]+?[\\d]*[:space:]*>+").unwrap();
    for caps in re.captures_iter(html) {
        if let Some(cap) = caps.at(0) {
            let tag = cap
                .trim_matches('<')
                .trim_matches('>')
                .to_lowercase();
            let count = result.get(&tag).unwrap_or(0) + 1;
            result.insert(tag, count);
        }       
    }    
    result
}

我还更改了代码以使其更加惯用( if let 而不是 if something.is_none()unwrap_or() 而不是可变局部变量等)。这或多或少是对您的原始代码的直接翻译。

至于用正则表达式解析 HTML,我忍不住提供了一个链接 to this answer .认真考虑使用适当的 HTML 解析器而不是依赖正则表达式。

关于html - 编写 HTML 解析器时借用的值不够长,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35656029/

相关文章:

c++ - 在 dynamic_casting 之后删除指针是否安全?

html - 按钮在 Canvas 上居中

java - 动态表单,带或不带多部分/表单数据

Javascript 正则表达式包含

javascript - JS react : replacing regex with component in a string

jquery - javascript或jquery相当于PHP的strtok()?

c - 释放指向 'double' 值的指针

html - 谷歌地图 JavaScript 错误

javascript - 具有多个下拉菜单的子菜单关闭延迟

比较 C/C++ 中的指针(字符数组)