2015-06-12 2 views
10

Я хочу получить первый символ std::str. Метод char_at() в настоящее время нестабилен, как и slice_chars в std::string::String.Получение одиночного символа из строки

Единственный вариант, который у меня есть в настоящее время, заключается в следующем.

let text = "hello world!"; 
let char_vec:Vec<char> = text.chars().collect(); 
let ch = char_vec[0]; 

Но это кажется чрезмерным, чтобы просто получить один символ, а не использовать остальную часть вектора.

ответ

30

UTF-8 не определяет, что такое «символ», так что это зависит от того, что вы хотите. В этом случае char s являются сканирующими значениями Unicode, и поэтому первый из &str будет составлять от одного до четырех байтов.

Если вы хотите только первый char, то не собирают в Vec<char>, просто использовать итератор:

let text = "hello world!"; 
let ch = text.chars().next().unwrap(); 
+3

Возможно, вы также захотите посмотреть, действительно ли вы хотите первый _grapheme_. – moveaway00

+1

Это дает блок кода 'n'th, но' char_at' дает блок кода, начинающийся с байта 'n'. Последнее более полезно, поскольку большинство строковых операций имеют дело с байтовыми индексами. Это эквивалентно 'char_at' (а также постоянному времени):' text [i ..]. Chars(). Next(). Unwrap() ' – delnan

+2

@delnan: Я бы сказал, что фактически использование' char_at' немного опасно поскольку индекс может быть * в * блоке кода. –

-1

Принятый ответ является немного некрасиво!

let text = "hello world!"; 

let ch = &text[0..1]; // this returns "h" 
+0

Этот ответ ** совершенно неверен ** для данных, отличных от ASCII. Попробуйте '&" 日本語 "[0 ..1] ' – Shepmaster

+1

Возможно, Стив Клабник, написавший принятый ответ, должен обновить свою книгу, которая показана на веб-сайте Rust, потому что она показывает этот точный метод (https://doc.rust-lang.org/book/second-edition/ch04 -03-slices.html # строковые-ломтики). – FeFiFoFu

+0

Это кратко описано в этой главе книги («*' world »будет срезом, который содержит указатель ** на 6-й байт **' s' и значение длины 5 *, акцент мой) и в [более подробно позже] (https://doc.rust-lang.org/book/second-edition/ch08-02-strings.html#bytes-and-scalar-values-and-grapheme-clusters-oh- мой). – Shepmaster

0

Я написал функцию, которая возвращает голову &str и остальное:

fn car_cdr(s: &str) -> (&str, &str) { 
    for i in 1..5 { 
     let r = s.get(0..i); 
     match r { 
      Some(x) => return (x, &s[i..]), 
      None =>(), 
     } 
    } 

    (&s[0..0], s) 
} 

использовать его как это:

let (first_char, remainder) = car_cdr("test"); 
println!("first char: {}\nremainder: {}", first_char, remainder); 

Выход выглядит следующим образом:

first char: t 
remainder: est 

Работает f ine с символами более 1 байт.

+0

Кажется, что [как это было бы проще] (https://play.rust-lang.org/?gist=c1a86a9de2b277ce571e5186eae85b7c&version=stable). – Shepmaster

+0

Shepmaster - ваша версия действительно проще. Но меня беспокоит функция chars() - мне кажется, что она сканирует всю строку и анализирует ее в вектор или что-то в этом роде, тогда как мой код смотрит не более, чем на первые четыре символа строки. Но, возможно, я не понимаю, как работает char()? – Sean

+0

Извините, что означает «первые 4 байта», а не «первые 4 символа» – Sean

Смежные вопросы