Поросячья латынь переводчик слишком много `push_str по


Я изучаю Rust и одной из задач в книге было построить поросячья латынь переводчик.

Преобразования строк в "поросячью латынь". Первые согласные каждого слова переносятся в конец слова и “Ай”, что “первый” будет “ИРСТ-фай.” Слова, которые начинаются с гласной у “Сенной” добавлен в конце вместо (“яблоко” превращается в “Эппл-Ай”).

Я придумал код ниже и я ищу пути ее совершенствования, в частности, уменьшения push_strS и улучшение starts_with_a_vowel метод. Как код может быть улучшен?

главная.РС

extern crate unicode_segmentation;
use unicode_segmentation::UnicodeSegmentation;

fn main() {
    println!("{}", pig_latinify("String me".to_string()));
}

fn transform_word(word: &str) -> String {
    let mut new_word = String::new();
    new_word.push_str(&word[1..]);
    new_word.push_str(&word[..1]);
    if starts_with_a_vowel(word) {
        new_word.push_str("h");
    }
    new_word.push_str("ay");
    new_word
}

fn starts_with_a_vowel(word: &str) -> bool {
    let vowels = ["a", "e", "i", "o", "u"];
    for vowel in &vowels {
        if word.starts_with(vowel) {
            return true;
        }
    }
    false
}

fn pig_latinify(statement: String) -> String {

    let mut transformed_statement = String::new();
    if !statement.is_ascii() {
        panic!("statement must be ascii");
    }
    let iter = statement.split_word_bounds();
    for word in iter {
        if word.trim().len() > 0 {
            transformed_statement.push_str(&transform_word(word));
            transformed_statement.push_str(" ");
        }
    }
    transformed_statement.trim();
    transformed_statement
}

Грузов.томл

...
[dependencies]
unicode-segmentation = "1.2.0"


154
2
задан 29 марта 2018 в 09:03 Источник Поделиться
Комментарии
1 ответ

Писать тесты

К сожалению, Ваш piglatify не следовать вашим правилам. apple трансформируется в applyaayно она должна трансформироваться в apple-hay. Кроме того, first должны трансформироваться в irst-fayно вы можете превратить его в irstfay.

Руст делает его очень легко добавить тесты на свой код:

#[cfg(test)]
mod test {
use transform_word;

#[test]
fn empty_string() {
assert_eq!(transform_word(""), "");
}

#[test]
fn apple() {
assert_eq!(transform_word("apple"), "apple-hay");
}

#[test]
fn first() {
assert_eq!(transform_word("first"), "irst-fay");
}
}

В то время как это только использует заданные строки из учения, это уже говорит нам, что есть что-то неладное, если мы проводим тесты с cargo test:


бег 3 тесты
тест тест::empty_string ... не удалось
тест тест::первая ... не
тест::яблоко ... не удалось

неудачи:

---- тест::empty_string поток stdout ----
темы теста::empty_string' в панике 'индекс байта 1 выходят за границы `', /проверки/ГРЦ/libcore/ул./мод.РС:2217:9
Примечание: запускать с RUST_BACKTRACE=1` для отладки.

---- тест::первый поток stdout ----
темы теста::первый запаниковал на утверждение не удалось: `(слева == правый)`
слева: "irstfay"`,
справа: `"ИРСТ-Фэй"`, src/главная.РС:57:9

---- тест::яблоко поток stdout ----
темы теста::яблоко' в панике на утверждение не удалось: `(слева == правый)`
слева: "ppleahay"`,
справа: "яблоко-Ай"`, src/главная.РС:52:9

Использовать with_capacity если возможно

Вы можете использовать String::with_capacity в transform_word. Новое слово имеет такую же длину, как и старый, плюс четыре:

fn transform_word(word: &str) -> String {
if word.is_empty() {
return String::new();
}
let mut new_word = String::with_capacity(word.len() + 4);

// still buggy, see above
new_word.push_str(&word[1..]);
new_word.push_str(&word[..1]);
if starts_with_a_vowel(word) {
new_word.push_str("h");
}
new_word.push_str("ay");
new_word
}

Однако, нам все еще нужно исправить ошибки, описанные ранее:

fn transform_word(word: &str) -> String {
if word.is_empty() {
return String::new();
}
let mut new_word = String::with_capacity(word.len() + 4);

if starts_with_a_vowel(word) {
new_word.push_str(&word);
new_word.push_str("-hay");
new_word
} else {
new_word.push_str(&word[1..]);
new_word.push('-');
new_word.push_str(&word[..1]);
new_word.push_str("ay");
new_word
}
}

Альтернативные варианты

Честно говоря, это выглядит несколько глупо. Мы можем просто использовать += вместо push_strили даже +:

fn transform_word(word: &str) -> String {
if word.is_empty() {
return word.to_owned();
}
if starts_with_a_vowel(word) {
word.to_owned() + "-hay"
} else {
word[1..].to_owned() + "-" + &word[..1] + "ay"
}
}

Говоря об альтернативах, если вы используете any тогда starts_with_a_vowel можно записать в одну строку:

fn starts_with_a_vowel(word: &str) -> bool {
"aeiou".chars().any(|vowel| word.starts_with(vowel))
}

Обратите внимание, что мы используем Char как узор, а не String. starts_with работает с обоими, но этот вариант показывает наши намерения, чтобы соответствовать только один символ.

Собственности

Не нужно брать на себя ответственность за данный String в pig_latinify.

1
ответ дан 29 марта 2018 в 11:03 Источник Поделиться