2016-07-19 14 views
4

期待されるアプローチString.truncate(usize)は、Unicode文字を考慮していないため失敗します(これは、Rustが文字列をUnicodeとして扱うと考えると困惑します)。アサーション 'でパニック'​​文字列をN文字以下で切り詰めるにはどうすればよいですか?

let mut s = "ボルテックス".to_string(); 
s.truncate(4); 

スレッド 'が失敗しました:self.is_char_boundary(new_len)'

はさらに、truncateは常に望まれていない元の文字列を修正します。

私が考えているのは、charに変換してStringに集めることです。

fn truncate(s: String, max_width: usize) -> String { 
    s.chars().take(max_width).collect() 
} 

fn main() { 
    assert_eq!(truncate("ボルテックス".to_string(), 0), ""); 
    assert_eq!(truncate("ボルテックス".to_string(), 4), "ボルテッ"); 
    assert_eq!(truncate("ボルテックス".to_string(), 100), "ボルテックス"); 
    assert_eq!(truncate("hello".to_string(), 4), "hell"); 
} 

しかし、これは非常に重い手渡しを感じます。

+7

ユニコードは複雑です。 'char'(コードポイントに対応する)を単位とし、書記素クラスタではないと確信していますか? – delnan

+2

実際には、他の方向も有効です。UTF-8エンコーディングにかかる​​バイト数に制限を設けます。文字全体を切り捨てるように注意してください。—可能な限り多くの 'char'sを取りますNバイト)。これは人の文字数の認識とは一致しませんが、制限がストレージ動機付けされている場合(データベース列のサイズなど)は妥当です。 – delnan

答えて

11

あなたがdelnan's pointを読み、理解していることを確認してください:

Unicodeは複雑おかしくています。 char(コードポイントに相当)を単なるクラスプルクラスではないと確信していますか?

この答えの残りの部分は、あなたがcharない書記素を使用するための十分な理由を持っている前提としています。錆がUnicodeとして文字列を扱う考慮不可解である

これは正しくありません。錆は文字列をUTF-8と扱います。 UTF-8では、すべてのコードポイントが可変バイト数にマップされます。 "6文字"を "Nバイト"に変換するアルゴリズムはO(1)なので、標準ライブラリはそれを隠しません。

あなたは文字で文字列の文字をステップ実行し、その文字のバイトインデックスを取得するためにchar_indicesを使用することができます。

fn truncate(s: &str, max_chars: usize) -> &str { 
    match s.char_indices().nth(max_chars) { 
     None => s, 
     Some((idx, _)) => &s[..idx], 
    } 
} 

fn main() { 
    assert_eq!(truncate("ボルテックス", 0), ""); 
    assert_eq!(truncate("ボルテックス", 4), "ボルテッ"); 
    assert_eq!(truncate("ボルテックス", 100), "ボルテックス"); 
    assert_eq!(truncate("hello", 4), "hell"); 
} 

また、これはあなたが必要な場合は、新たな割り当てに移動するかを選択することができたスライスを返します。またはStringを変更してください:

// May not be as efficient as inlining the code... 
fn truncate_in_place(s: &mut String, max_chars: usize) { 
    let bytes = truncate(&s, max_chars).len(); 
    s.truncate(bytes); 
} 

fn main() { 
    let mut s = "ボルテックス".to_string(); 
    truncate_in_place(&mut s, 0); 
    assert_eq!(s, ""); 
} 
+0

私の 'chars()'とは違う 'char_indices()'の使い方は? –

+2

@Peter 'chars'は文字を返します。 'char_indices'は、元の' str'で始まる 'u8'の実際のインデックスを返す以外は、' chars()。enumerate() 'と似ています。 – LinearZoetrope

+1

'.skip(max_chars).next()'→ '.nth(max_chars)'です。 @Veedrac Every。 – Veedrac

関連する問題