본문 바로가기
개발/러스트 (Rust)

Rust 기본 : UTF-8 문자열 (Strings)

by 레조 2024. 7. 17.

https://rustacean.net/

 

Rust 기본 : UTF-8 문자열 (Strings)

 

러스트는 기본 문자열 타입으로 UTF-8을 사용합니다.

UTF (Unicode Transformation Format)

 

&str, 문자열 슬라이스 (주소, 길이)
 - &str은 문자열의 일부를 보거나 참조할 수 있지만, 내용을 변경할 수는 없습니다.
 - &str은 UTF-8로 인코딩된 바이트의 연속을 참조하는 슬라이스입니다.
 - 문자열 슬라이스는 실제 데이터를 소유하지 않고, 기존 데이터에 대한 참조만을 가집니다.

 

String (주소, 길이, 용량)
 - String은 크기를 조정할 수 있으며, 내용을 수정하거나 추가할 수 있는 UTF-8로 인코딩된 문자열입니다.
 - String 타입은 Rust의 표준 라이브러리에 포함되어 있으며, 메모리 관리와 관련된 여러 기능을 제공합니다.

use unicode_segmentation::UnicodeSegmentation;

fn main() {
    println!("----- UNICODE ----------");
    println!("crab: {}", '\u{1F980}'); // rust 🦀
    let rust = "🦀";
    let utf8_bytes = rust.as_bytes();
    for byte in utf8_bytes {
        print!("{:08b} ", byte);
    }
    println!();

    println!("----- Create String ----------");
    let s1 = "안녕 세계야! 🦀";
    let s2 = String::from("안녕 세계야!");
    let s3 = "안녕 세계야!".to_string();
    let s4 = "안녕 세계야!".to_owned();
    let s5 = &s4[..];
    println!("{s5}");

    println!("----- Manipulate String ----------");
    let mut s = String::from("foo");
    s.push_str(" bar");
    println!("{s}");
    s.replace_range(.., "baz");
    println!("{s}");

    println!("----- Concatenating String ----------");
    // + operator
    let s1 = String::from("Hello, ");
    let s2 = String::from("World!");
    // let s3 = s1 + &s2; // s1 소유권이 이동하기 때문에 다음 코드를 위해 주석처리.
    // println!("{s3}");
    let s4 = format!("{}-{}", s1, s2);
    println!("{s4}");

    let s1 = ["first", "second"].concat();
    let s2 = format!("{}{}", "first", "second");
    let s3 = concat!("first", "second");

    let s4 = String::from("test");
    let s5 = s4 + "okok"; // String type must be first

    println!("----- Indexing String ----------");
    let s1 = "🦀🦀🦀🦀🦀";
    let s2 = &s1[0..4];
    println!("{s2}");

    print!("bytes: ");
    for b in "नमस्ते".bytes() {
        print!("{b} ");
    }
    println!();

    // Scalar values are a basic unit in Unicode,
    // and some user perceive characters are made up of multiple scaler values.
    // chars() : Iterator over the unicode scaler values of the string.
    print!("chars: ");
    for c in "नमस्ते".chars() { // 유니코드 글자 단위 스칼라 값
        print!("{c} ");
    }
    println!();

    // In unicode, user perceived characters are known as grapheme clusters.
    // cf) cargo add unicode-segmentation
    // graphemes() : Iterator over the grapheme clusters
    print!("graphemes: ");
    for g in "नमस्ते".graphemes(true) { // 사용자 인식 문자 출력
        print!("{g} ");
    }
    println!();

    // Strings and function
    let s1 = "Hello World!";
    let s2 = String::from("Hello World!");
    my_function(s1);
    my_function(&s2); // deref coercion


    // RUST UTF-8 코드의 문자열 찾기 성능이 linear 하다.
    // Go 는 UCS4 Room 타입을 사용하여 문자열 찾기 성능을 constant 하게 향상한다.

}

// String 으로 리턴하는 이유는, 호출자가 스트링 ownership 획득을 위해서.
fn my_function(a: &str) -> String {
    return format!("{}", a); // clone and ownership moved
}

 


 

UTF-8
1 character = 1 ~ 4 bytes
1,112,064 characters.

1 byte 문자 : ASCII

2 byte 문자 : 추가 라틴 문자, 히브리어, 아랍어

3 byte 문자 : 비 라틴 문자 세트, 한글, 가나, 간체

4 byte 문자 : 보조 다국어 평면 및 특수 목적 평면, 이모지, 역사적 스크립트 등.

 

🦀 이모지 UTF-8 코드 포인트(U+)  범위는 아래와 같다.

종류 범위 개수 설명
Emoji Symbols U+1F300 - U+1F5FF 768 일반적인 이모지로 기호, 동물, 자연 현상, 음식, 스포츠 등을 포함
Emoticons (Emotional Icons) U+1F600 - U+1F64F 80 얼굴 표현 중심의 감정을 나타내는 이모지
Transport and Map Symbols U+1F680 - U+1F6FF 128 교통 수단과 지도 기호 관련 이모지
Miscellaneous Symbols and Pictographs U+1F900 - U+1F9FF 256 다양한 기호, 유물, 판타지 캐릭터 등을 포함하는 추가적인 이모지
Supplemental Symbols and Pictographs U+1FA70 - U+1FAFF 144 더 많은 활동, 새로운 동물, 기호 등을 포함하는 이모지
Extended Pictographic U+1F000 - U+1F02F 48 주로 게임과 관련된 기호와 일부 전통 게임에서 사용되는 이모지

 

UTF-8 코드 변환

1 ~ 4 바이트 코드 포인트 변환 포멧


1 byte : 0xxxxxxx
2 byte : 110xxxxx 10xxxxxx
3 byte : 1110xxxx 10xxxxxx 10xxxxxx
4 byte : 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx

 

위의 바이트 구성에서 x 부분만 따로 비트 취합하여 4 비트씩 끊어서 계산하면,

코드 포인트 U+ 범위는 아래와 같다.

 

1 byte = 0x00 ~ 0x7F

2 byte = 0x80 ~ 0x7FF

3 byte = 0x800 ~ 0xFFFF

4 byte = 0x10000 ~ 0x10FFFF

 

이제 예를 들어 문자 주소를 코드 포인트로 변환해보자.

 

Crab emoji : 4바이트 문자, 🦀
4 바이트 주소 구성 : 11110000 10011111 10100110 10000000

4 바이트 코드 포인트 변환 포멧 : 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx

4 바이트 문자일 경우 변환 포멧의 x 부분의 주소 비트를 취합한다.
000 011111 100110 000000


이제 오른쪽 부터 4비트씩 끊어서 표기하면 코드 포인트가 된다.
0001 1111 1001 1000 0000

 

16진수로 변환

U+1F980

 

러스트 코드에서는 아래처럼 사용한다. \u{1F980}

println!("{}", '\u{1F980}'); 🦀