我写了一个函数来提示输入并返回结果。在此版本中,返回的字符串包含用户的尾随换行符。我想要删除该换行符(并且只是换行符):
fn read_with_prompt(prompt: &str) -> io::Result<String> {
let stdout = io::stdout();
let mut reader = io::stdin();
let mut input = String::new();
print!("{}", prompt);
stdout.lock().flush().unwrap();
try!(reader.read_line(&mut input));
// TODO: Remove trailing newline if present
Ok(input)
}
仅删除单个尾随换行符的原因是此函数还将用于提示输入密码(适当使用termios以停止回显),如果某人的密码有尾随空格,则应保留此密码
在关于如何在字符串末尾实际删除单个换行符之后,我最终使用了trim_right_matches
。但是返回&str
。我尝试使用Cow
来解决此问题,但错误仍然表明input
变量的存活时间不够长。
fn read_with_prompt<'a>(prompt: &str) -> io::Result<Cow<'a, str>> {
let stdout = io::stdout();
let mut reader = io::stdin();
let mut input = String::new();
print!("{}", prompt);
stdout.lock().flush().unwrap();
try!(reader.read_line(&mut input));
let mut trimmed = false;
Ok(Cow::Borrowed(input.trim_right_matches(|c| {
if !trimmed && c == '\n' {
trimmed = true;
true
}
else {
false
}
})))
}
错误:
src/main.rs:613:22: 613:27 error: `input` does not live long enough
src/main.rs:613 Ok(Cow::Borrowed(input.trim_right_matches(|c| {
^~~~~
src/main.rs:604:79: 622:2 note: reference must be valid for the lifetime 'a as
defined on the block at 604:78...
src/main.rs:604 fn read_with_prompt<'a, S: AsRef<str>>(prompt: S) -> io::Resul
t<Cow<'a, str>> {
src/main.rs:605 let stdout = io::stdout();
src/main.rs:606 let mut reader = io::stdin();
src/main.rs:607 let mut input = String::new();
src/main.rs:608 print!("{}", prompt.as_ref());
src/main.rs:609 stdout.lock().flush().unwrap();
...
src/main.rs:607:35: 622:2 note: ...but borrowed value is only valid for the bl
ock suffix following statement 2 at 607:34
src/main.rs:607 let mut input = String::new();
src/main.rs:608 print!("{}", prompt.as_ref());
src/main.rs:609 stdout.lock().flush().unwrap();
src/main.rs:610 try!(reader.read_line(&mut input));
src/main.rs:611
src/main.rs:612 let mut trimmed = false;
...
基于previous questions along these lines,似乎这是不可能的。是唯一一个分配删除了尾部换行符的新字符串的选项吗?似乎应该有一种方法来修剪字符串而不复制它(在C中你只需用'\n'
替换'\0'
)。
答案 0 :(得分:11)
您可以使用String::pop
或String::truncate
:
fn main() {
let mut s = "hello\n".to_string();
s.pop();
assert_eq!("hello", &s);
let mut s = "hello\n".to_string();
let len = s.len();
s.truncate(len - 1);
assert_eq!("hello", &s);
}
答案 1 :(得分:8)
比接受的解决方案更通用的解决方案,适用于任何类型的行结尾:
fn main() {
let mut s = "hello\r\n".to_string();
let len_withoutcrlf = s.trim_right().len();
s.truncate(len_withoutcrlf);
assert_eq!("hello", &s);
}
答案 2 :(得分:4)
strip_suffix
这将删除一个尾随的 \r\n
或 \n
:
fn strip_trailing_newline(input: &str) -> &str {
input
.strip_suffix("\r\n")
.or(input.strip_suffix("\n"))
.unwrap_or(&input)
}
一些测试:
#[test]
fn strip_newline_works(){
assert_eq!(strip_trailing_newline("Test0\r\n\r\n"), "Test0\r\n");
assert_eq!(strip_trailing_newline("Test1\r\n"), "Test1");
assert_eq!(strip_trailing_newline("Test2\n"), "Test2");
assert_eq!(strip_trailing_newline("Test3"), "Test3");
}
答案 3 :(得分:1)
一种在不重新分配字符串的情况下剥离单个尾随换行符的跨平台方法是:
fn trim_newline(s: &mut String) {
if s.ends_with('\n') {
s.pop();
if s.ends_with('\r') {
s.pop();
}
}
}
这将从字符串的末尾剥离"\n"
或"\r\n"
,但不附加空格。
答案 4 :(得分:0)
编辑:我刚刚意识到OP希望不制作字符串的副本......所以只需注意这实际上复制了字符串。 :(
我是 Rust 新手,所以我不知道这个功能是什么时候引入的,但可以考虑使用 String::lines
方法。看起来它应该以可靠的方式跨平台工作,并且在我的本地开发中,它的行为似乎符合 OP 的要求。
use std::io::stdin;
fn main() {
println!("Enter a line of text:");
let mut buf = String::new();
stdin().read_line(&mut buf).expect("Failed to read input.");
let my_str = buf.lines()
.next().expect("Could not read entry.");
println!("You entered: [{}]", my_str);
}
参考:https://doc.rust-lang.org/stable/std/string/struct.String.html#method.lines