String 是否有类似JavaScript的方法';它生锈了吗?
我查看了锈迹,但找不到提取子串的方法 Rust中是否有类似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!";
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..));
}