Rust String is not a String [duplicate] - string

This question already has answers here:
Why does my string not match when reading user input from stdin?
(3 answers)
Closed 6 years ago.
I use String::from("string") to get a String
let dog = String::from("dog")
and
dog == String::from("dog")
returns false. Even in pattern matching.
match dog.as_ref() {
"dog" => println!("Dog is a dog"), //no output
_ => println!("Dog is not a dog")
}
What is wrong?
Example
use std::io;
fn main() {
let mut sure = String::from("");
println!("Hello, world!");
println!("Are you sure(Y/N)");
io::stdin().read_line(&mut sure).expect("Failed");
println!("sure {}", sure );
let surely = {sure == String::from("Y")};
println!("surely {} ", surely ); //this line output is "surely false"
if surely {
dog_loop("HA");
}
}

As a general rule, when comparing Strings in Rust, it's better to turn the string into a &str for comparison against a string literal, rather than converting the string literal into a String. The reason for this is that the latter requires object creation (allocating for a String), while the first doesn't, and so it's more efficient.
The specific problem you are seeing here comes from the fact that your input does not have excess whitespace stripped. After the line
io::stdin().read_line(&mut sure).expect("Failed");
The value of sure is not "Y" as you might expect, but is actually "Y\n" on Unix, or "Y\r\n" on Windows. You can compare this directly by modifying your comparison as so:
let surely = {sure.as_str() == "Y\n"};
println!("surely {} ", surely );
And you will see it return "surely true". However, this makes your code platform-dependent. Preferably, use the string method String.trim(), which will remove the trailing whitespace.

Related

Palindrome code in rust programming language

I am trying to write a palindrome program in Rust.
Even when the input is a palindrome word, my attempt is not showing a palindrome:
use std::io;
fn main(){
println!("enter a word to know if palindrome or not");
let mut inp=String::new();
io::stdin().read_line(&mut inp).expect("needed a string");
let arr:Vec<_>=inp.chars().collect();
let mut new_st=String::new();
for i in 0..arr.len(){
new_st.push(arr[arr.len()-1-i]);
}
if inp.eq(&new_st[1..]) {
println!("Palindrome");
}
else{
println!("not a palindrome..");
}
println!("{}",&new_st[1..]);
}
Output:
enter a word to know if palindrome or not
amma
not a palindrome..
amma
The problem is that the .read_line() function adds a \n to the end of inp string. You should remove it from the string or better yet use the .trim() method on the String to strip out any newline or whitespace characters.
inp = inp.trim().to_string();
Just some more improvement on your code, you should leverage Rust's iterators to reverse the String faster rather than manually doing it.
You can write this:-
let rev = inp.chars().rev().collect::<String>();
This iterates over all the characters in the inp string and reverses them in order. Finally it collects them into a String that is stored in the rev variable.
Also, you should use == rather than using the .eq() operator, it's just much more clearer.
See this playground link for complete code

Simpler way to check if string start with a digit in Rust?

What I am currently using is this
fn main() {
let a = "abc123";
let b = "1a2b3c";
println!("{}", a[0..1].chars().all(char::is_numeric));
println!("{}", b[0..1].chars().all(char::is_numeric));
}
Are there a more idiomatic and/or simpler way to do this?
Note: The string is guaranteed to be non empty and made of ASCII characters.
If you are sure that it is non-empty and made out of ascii, you can operate directly on bytes (u8):
a.as_bytes()[0].is_ascii_digit()
or
(b'0'..=b'9').contains(&a.as_bytes()[0])
More general setting (and, in my opinion, more idiomatic):
a.chars().next().unwrap().is_numeric()
The reason all this looks a bit unwieldy is that there may be some things going wrong (that are easily overlooked in other languages):
string might be empty => leads us into Option/unwrap-land
strings in rust are UTF-8 (which basically complicates random-accessing into string; note that rust does not only consider 0-9 as numeric, as shown here)
Starting from your original solution and parse:
fn main() {
let a = "abc123";
let b = "1a2b3c";
println!("{:?}", a[0..1].parse::<u8>().is_ok()); // false
println!("{:?}", b[0..1].parse::<u8>().is_ok()); // true
}
If the first character is guaranteed to be ASCII and the string is not empty.
Playground

Why does a string read from stdin never match the strings I compare it to? [duplicate]

This question already has answers here:
Why does my string not match when reading user input from stdin?
(3 answers)
Closed 4 years ago.
I am trying to match on a user-supplied string with this code:
use std::io;
fn main() {
let mut input = String::new();
io::stdin().read_line(&mut input).expect("Failed to read line.");
match input.as_ref(){
"test" => println!("That was test"),
_ => print!("Something's wrong"),
}
}
However, this code always prints "Something's wrong", even when I enter "test". How can I make this work as intended?
This doesn't match "test" even if (it looks like) you enter "test" because you're also inputting a new line by hitting Enter, so input will actually contain "test\n".
You can solve this by removing the trailing newline using trim_end:
match input.trim_end() {
"test" => println!("Great!"),
_ => println!("Too bad")
}
This won't modify the original string, though.

How can I convert a one element string into a char? [duplicate]

This question already has answers here:
How do I get the first character out of a string?
(7 answers)
Closed 2 years ago.
I need to convert a one element &str into char. I was able to come up with this solution that also works for String:
fn main() {
let comma: &str = ",";
let my_char = comma.chars().nth(0).unwrap();
assert_eq!(my_char, ',');
}
Is there a better or shorter way to do it?
No huge improvements I can think of, but a few notes:
You could replace .nth(0) with .next(), which does basically the same thing.
You should ideally not use .unwrap(), since if the string is empty, your program will panic.
If you really must panic, ideally use .expect("msg"), which will give users a better idea of why you panicked.
Taking those together:
fn main() {
let comma: &str = ",";
let my_char = comma.chars().next().expect("string is empty");
assert_eq!(my_char, ',');
}
The only other thing to note is that "one element" is a somewhat dangerous thing to talk about. For example, "é" has one char, but "é" has two (the first is a pre-composed U+00E9, whilst the second is a regular e followed by a U+0301 combining ◌́).

How to iterate through characters in a string in Rust to match words?

I'd like to iterate through a sentence to extract out simple words from the string. Here's what I have so far, trying to make the parse function first match world in the input string:
fn parse(input: String) -> String {
let mut val = String::new();
for c in input.chars() {
if c == "w".to_string() {
// guessing I have to test one character at a time
val.push_str(c.to_str());
}
}
return val;
}
fn main() {
let s = "Hello world!".to_string();
println!("{}", parse(s)); // should say "world"
}
What is the correct way to iterate through the characters in a string to match patterns in Rust (such as for a basic parser)?
Checking for words in a string is easy with the str::contains method.
As for writing a parser itself, I don't think it's any different in Rust than other languages. You have to create some sort of state machine.
For examples, you could check out serialize::json. I also wrote a CSV parser that uses a buffer with a convenient read_char method. The advantage of using this approach is that you don't need to load the whole input into memory at once.

Resources