String 是否有类似JavaScript的方法';它生锈了吗?

String 是否有类似JavaScript的方法';它生锈了吗?,string,substring,rust,String,Substring,Rust,我查看了锈迹,但找不到提取子串的方法 Rust中是否有类似JavaScript的方法?如果没有,您将如何实施 str.substr(start[, length]) 最近的可能是slice\u unchecked,但它使用字节偏移量而不是字符索引,并且标记为safe对于字符,可以使用s.chars().skip(pos).take(len): 不过要注意Unicode字符的定义 对于字节,可以使用切片语法: fn main() { let s = b"Hello, world!";

我查看了锈迹,但找不到提取子串的方法

Rust中是否有类似JavaScript的方法?如果没有,您将如何实施

str.substr(start[, length])

最近的可能是
slice\u unchecked
,但它使用字节偏移量而不是字符索引,并且标记为
safe
对于字符,可以使用
s.chars().skip(pos).take(len)

不过要注意Unicode字符的定义

对于字节,可以使用切片语法:

fn main() {
    let s = b"Hello, world!";
    let ss = &s[7..12];
    println!("{:?}", ss);
}
在踩下迭代器后,可以使用迭代器上的方法返回
&str
切片。因此,要跳过第一个
start
字符,可以调用

let s = "Some text to slice into";
let mut iter = s.chars();
iter.by_ref().nth(start); // eat up start values
let slice = iter.as_str(); // get back a slice of the rest of the iterator
现在,如果还想限制长度,则首先需要计算
长度
字符的字节位置:

let end_pos = slice.char_indices().nth(length).map(|(n, _)| n).unwrap_or(0);
let substr = &slice[..end_pos];

这可能会让人觉得有点迂回,但生锈并不会对您隐藏任何可能占用CPU周期的内容。也就是说,我想知道为什么还没有提供
substr
方法的板条箱。

对于
my_字符串。substring(start,len)
类似于语法,您可以编写一个自定义特征:

trait StringUtils {
    fn substring(&self, start: usize, len: usize) -> Self;
}

impl StringUtils for String {
    fn substring(&self, start: usize, len: usize) -> Self {
        self.chars().skip(start).take(len).collect()
    }
}

// Usage:
fn main() {
    let phrase: String = "this is a string".to_string();
    println!("{}", phrase.substring(5, 8)); // prints "is a str"
}

此代码执行子字符串和字符串切片,而不会出现恐慌或分配:

use std::ops::{Bound, RangeBounds};

trait StringUtils {
    fn substring(&self, start: usize, len: usize) -> &str;
    fn slice(&self, range: impl RangeBounds<usize>) -> &str;
}

impl StringUtils for str {
    fn substring(&self, start: usize, len: usize) -> &str {
        let mut char_pos = 0;
        let mut byte_start = 0;
        let mut it = self.chars();
        loop {
            if char_pos == start { break; }
            if let Some(c) = it.next() {
                char_pos += 1;
                byte_start += c.len_utf8();
            }
            else { break; }
        }
        char_pos = 0;
        let mut byte_end = byte_start;
        loop {
            if char_pos == len { break; }
            if let Some(c) = it.next() {
                char_pos += 1;
                byte_end += c.len_utf8();
            }
            else { break; }
        }
        &self[byte_start..byte_end]
    }
    fn slice(&self, range: impl RangeBounds<usize>) -> &str {
        let start = match range.start_bound() {
            Bound::Included(bound) | Bound::Excluded(bound) => *bound,
            Bound::Unbounded => 0,
        };
        let len = match range.end_bound() {
            Bound::Included(bound) => *bound + 1,
            Bound::Excluded(bound) => *bound,
            Bound::Unbounded => self.len(),
        } - start;
        self.substring(start, len)
    }
}

fn main() {
    let s = "abcdèfghij";
    // All three statements should print:
    // "abcdè, abcdèfghij, dèfgh, dèfghij."
    println!("{}, {}, {}, {}.",
        s.substring(0, 5),
        s.substring(0, 50),
        s.substring(3, 5),
        s.substring(3, 50));
    println!("{}, {}, {}, {}.",
        s.slice(..5),
        s.slice(..50),
        s.slice(3..8),
        s.slice(3..));
    println!("{}, {}, {}, {}.",
        s.slice(..=4),
        s.slice(..=49),
        s.slice(3..=7),
        s.slice(3..));
}
使用std::ops::{Bound,RangeBounds};
特征弦{
fn子字符串(&self,start:usize,len:usize)->&str;
fn切片(&self,范围:impl RangeBounds)->&str;
}
str的impl StringUtils{
fn子字符串(&self,开始:usize,len:usize)->&str{
设mut char_pos=0;
让mut byte_start=0;
让mut it=self.chars();
环路{
如果char_pos==start{break;}
如果让Some(c)=it.next(){
char_pos+=1;
字节_start+=c.len_utf8();
}
else{break;}
}
char_pos=0;
让mut byte_end=byte_start;
环路{
如果char_pos==len{break;}
如果让Some(c)=it.next(){
char_pos+=1;
字节_end+=c.len_utf8();
}
else{break;}
}
&self[字节开始..字节结束]
}
fn切片(&self,范围:impl RangeBounds)->&str{
让start=匹配范围。start\u-bound(){
绑定::包含(绑定)|绑定::排除(绑定)=>*绑定,
绑定::无界=>0,
};
设len=匹配范围。end_bound(){
绑定::包含(绑定)=>*绑定+1,
绑定::已排除(绑定)=>*绑定,
Bound::Unbounded=>self.len(),
}-启动;
self.substring(开始,len)
}
}
fn main(){
设s=“abcdèfghij”;
//所有三项声明均应打印:
//“快,快,快,快,快。”
println!(“{},{},{},{},{}.”,
s、 子串(0,5),
s、 子串(0,50),
s、 子串(3,5),
s、 子串(3,50));
println!(“{},{},{},{},{}.”,
s、 切片(…5),
s、 切片(…50),
s、 切片(3..8),
s、 切片(3…);
println!(“{},{},{},{},{}.”,
s、 切片(..=4),
s、 切片(..=49),
s、 切片(3..=7),
s、 切片(3…);
}

您也可以使用
.to_string()[]

本例获取原始字符串的一个不可变片段,然后对该字符串进行变异,以证明原始片段被保留

让mut s:String=“你好,世界!”。to_String();
让子字符串:&str=&s.to_string()[…6];
s、 替换_范围(…6,“再见,”);
普林顿!(“{}{}宇宙!”,s,子串);
//再见,世界!你好,宇宙!

oli_obk给出的解决方案不处理字符串切片的最后一个索引。它可以用
.chain(一次(s.len())
固定

这里的函数
substr
实现了一个带有错误处理的子字符串切片。如果将无效索引传递给函数,则返回字符串片段的有效部分,并带有
Err
-variant。所有拐角处的箱子都应正确处理

fn substr(s:&str,begin:usize,length:Option)->Result{
使用std::iter::一次;
设mut itr=s.char_index().map(|(n,|)n).chain(一次(s.len());
设beg=itr.N(开始);
如果你乞求,你就没有了{
返回错误(“”);
}如果长度==某些(0),则为else{
返回Ok(“”);
}
设end=length.map_或(Some(s.len()),| l | itr.nth(l-1));
如果让一些(结束)=结束{
返回Ok(&s[beg.unwrap()…end]);
}否则{
返回错误(&s[beg.unwrap()…s.len()]);
}
}

let s=“abc我建议您使用板条箱。(如果您想了解如何正确操作,请查看。)

没有看到
chars()
,谢谢!是否也可以将字符索引映射到字节偏移量并从中创建一个片段?@laktak,您可以使用
str::char\u索引来实现此目的。在第二个示例中,我想您的意思是
b“你好,世界!“
?“不会对您隐藏任何可能占用CPU周期的内容”-您能解释一下为什么substr可能比它拥有的任何修剪函数都要昂贵吗?嗯……修剪函数预计会消除它们遇到的所有空白。这是一个O(n)定义的操作。但是使用
substr
方法,用户可能会假定它是O(1),因为他们正在输入索引。只是疯狂:)这不像JavaScript:
“ウィキペディアへようこそ.substr(1,3)
vs
&ウィキペディアへようこそ“[1..3]
。一个“起作用”,另一个则不起作用。@Shepmaster更正。这并不适用于所有字符。
跳过.take.collect
方法非常理想。
use std::ops::{Bound, RangeBounds};

trait StringUtils {
    fn substring(&self, start: usize, len: usize) -> &str;
    fn slice(&self, range: impl RangeBounds<usize>) -> &str;
}

impl StringUtils for str {
    fn substring(&self, start: usize, len: usize) -> &str {
        let mut char_pos = 0;
        let mut byte_start = 0;
        let mut it = self.chars();
        loop {
            if char_pos == start { break; }
            if let Some(c) = it.next() {
                char_pos += 1;
                byte_start += c.len_utf8();
            }
            else { break; }
        }
        char_pos = 0;
        let mut byte_end = byte_start;
        loop {
            if char_pos == len { break; }
            if let Some(c) = it.next() {
                char_pos += 1;
                byte_end += c.len_utf8();
            }
            else { break; }
        }
        &self[byte_start..byte_end]
    }
    fn slice(&self, range: impl RangeBounds<usize>) -> &str {
        let start = match range.start_bound() {
            Bound::Included(bound) | Bound::Excluded(bound) => *bound,
            Bound::Unbounded => 0,
        };
        let len = match range.end_bound() {
            Bound::Included(bound) => *bound + 1,
            Bound::Excluded(bound) => *bound,
            Bound::Unbounded => self.len(),
        } - start;
        self.substring(start, len)
    }
}

fn main() {
    let s = "abcdèfghij";
    // All three statements should print:
    // "abcdè, abcdèfghij, dèfgh, dèfghij."
    println!("{}, {}, {}, {}.",
        s.substring(0, 5),
        s.substring(0, 50),
        s.substring(3, 5),
        s.substring(3, 50));
    println!("{}, {}, {}, {}.",
        s.slice(..5),
        s.slice(..50),
        s.slice(3..8),
        s.slice(3..));
    println!("{}, {}, {}, {}.",
        s.slice(..=4),
        s.slice(..=49),
        s.slice(3..=7),
        s.slice(3..));
}