如何找到另一个字符串的子串的起始偏移量?

7

给定一个字符串和一个切片,切片是指某个子字符串,有没有可能找到该切片的起始和结束索引?

我有一个名为ParseString 的函数,它接受一个字符串引用,并尝试按照某些语法进行解析:

ParseString(inp_string: &str) -> Result<(), &str>

如果解析正确,结果就是Ok(()),但如果出现错误,则通常在某个子字符串中,并且错误实例为Err(e),其中e是该子字符串的一个片段。
当给出发生错误的子字符串时,我想说类似于“从字符x到y的错误”,其中x和y是错误子字符串的起始和结束索引。
我不想直接在Err中编码错误位置,因为我正在嵌套这些调用,而嵌套的切片中的偏移量可能与顶级字符串中的某些切片不对应。
2个回答

8
Rust实际上曾经有一种不稳定的方法来做到这一点,但是由于已经过时,它被删除了,这有点奇怪,因为替代方法根本没有相同的功能
话虽如此,实现并不复杂,所以你可以在代码的某个地方添加以下内容:
pub trait SubsliceOffset {
    /**
    Returns the byte offset of an inner slice relative to an enclosing outer slice.

    Examples

    ```ignore
    let string = "a\nb\nc";
    let lines: Vec<&str> = string.lines().collect();
    assert!(string.subslice_offset_stable(lines[0]) == Some(0)); // &"a"
    assert!(string.subslice_offset_stable(lines[1]) == Some(2)); // &"b"
    assert!(string.subslice_offset_stable(lines[2]) == Some(4)); // &"c"
    assert!(string.subslice_offset_stable("other!") == None);
    ```
    */
    fn subslice_offset_stable(&self, inner: &Self) -> Option<usize>;
}

impl SubsliceOffset for str {
    fn subslice_offset_stable(&self, inner: &str) -> Option<usize> {
        let self_beg = self.as_ptr() as usize;
        let inner = inner.as_ptr() as usize;
        if inner < self_beg || inner > self_beg.wrapping_add(self.len()) {
            None
        } else {
            Some(inner.wrapping_sub(self_beg))
        }
    }
}

如果您不需要支持旧版本的 Rust,可以删除 _stable 后缀;它只是为了避免与现在已删除的 subslice_offset 方法发生名称冲突。请保留 html 标签。

8
只要您的所有字符串切片都从同一个字符串缓冲区中借用,就可以使用简单的指针算术计算偏移量。您需要以下方法:
  • str::as_ptr():返回字符串切片开头的指针
  • 一种获取两个指针之间差异的方法。现在,最简单的方法是将两个指针都转换为usize(这始终是无操作),然后减去它们。在1.47.0+版本中,有一种稍微更好的方法offset_from()
下面是可工作的代码(Playground):
fn get_range(whole_buffer: &str, part: &str) -> (usize, usize) {
    let start = part.as_ptr() as usize - whole_buffer.as_ptr() as usize;
    let end = start + part.len();
    (start, end)
}

fn main() {
    let input = "Everyone ♥ Ümläuts!";
    
    let part1 = &input[1..7];
    println!("'{}' has offset {:?}", part1, get_range(input, part1));
    
    let part2 = &input[7..16];
    println!("'{}' has offset {:?}", part2, get_range(input, part2));
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接