Rust, 한글 2byte HEX En/Decoding
Rust는 기본적으로 UTF-8 중심으로 문자열을 처리한다.1 그러나 Windows는 euc-kr을 확장한 CP949 (MS949)와 Unicode로 한글을 처리하므로2 Windows에서는 영문, 숫자와 별개로 한글을 byte 단위로 처리할 때 2byte 또는 3byte의 문자가 혼재할 수 있다.
아래의 예제는 2byte (AnsiString) 한글만으로 Hex를 encode, decode 필요가 있을 때 참고할 만한 소스이다.
[dependencies]
encoding = "0.2.33"
hex = "0.4.2"
main.rs
use encoding::{label::encoding_from_whatwg_label, EncoderTrap, DecoderTrap};
use hex;
fn main() {
let kor_eng_num = String::from("가나다 ABC 123");
println!("{}", kor_eng_num);
println!("---------------------");
let mut vec = Vec::new();
let string_list = kor_eng_num.split_whitespace();
for s in string_list {
println!("UTF8: {} / MS949: {}", hex::encode(s).to_uppercase(), split_hex(s.into()));
vec.push(split_hex(s.into())); // s.into() -> &s
}
println!("---------------------");
for hex_str in vec.iter() {
println!("{} : {}", hex_str, hex2str(hex_str));
}
}
fn hex2str(s: &str) -> &str {
let euckr = encoding_from_whatwg_label("euc-kr").unwrap();
let decode_string = euckr.decode(&hex::decode(s).unwrap(), DecoderTrap::Replace).unwrap();
return string_to_static_str(decode_string);
}
fn split_hex(s: &str) -> &str { //&str -> String
let euckr = encoding_from_whatwg_label("euc-kr").unwrap();
//println!("{} / {:?}", euckr.name(), euckr.whatwg_name());
let encode_string = euckr.encode(&s, EncoderTrap::Replace).unwrap();
let hex_encode_string = hex::encode(encode_string).to_uppercase();
return string_to_static_str(hex_encode_string);
}
// 메모리 누수가 발생하는 함수
fn string_to_static_str(s: String) -> &'static str {
Box::leak(s.into_boxed_str())
}
/* 출력결과
가나다 ABC 123
---------------------
UTF8: EAB080EB8298EB8BA4 / MS949: B0A1B3AAB4D9
UTF8: 414243 / MS949: 414243
UTF8: 313233 / MS949: 313233
---------------------
B0A1B3AAB4D9 : 가나다
414243 : ABC
313233 : 123
*/
메모리 누수 함수 수정 대안
1.소유권을 그대로 넘기기
fn string_to_owned(s: String) -> String {
s // 그대로 반환 (소유권 이동)
}
2.라이프타임(Lifetime 'a) 사용하기
struct MyStruct<'a> {
name: &'a str,
}
fn process_str(s: &str) {
let item = MyStruct { name: s };
println!("{}", item.name);
}
3.공유 소유권(Arc 또는 Rc) 사용하기
use std::sync::Arc;
fn string_to_shared(s: String) -> Arc<str> {
Arc::from(s.into_boxed_str())
}
// 사용
let shared = string_to_shared(String::from("hello"));
// 참조 카운트 증가, 마지막 참조가 사라지면 자동 해제
let reference = Arc::clone(&shared);
4.런타임 상수가 필요하다면 (once_cell 또는 lazy_static)
use once_cell::sync::Lazy;
static GLOBAL_STR: Lazy<String> = Lazy::new(|| {
String::from("런타임에 생성된 전역 문자열")
});
Reference