はじめに
まったく何の役にも立ちませんが、
絵文字翻訳ツール的なものを作成してみました💪
今回作った絵文字翻訳ツール
- 絵文字=>英語名に変換
- 絵文字=>日本語名に変換
- 名称=>絵文字に変換
- 説明モード(絵文字のあとに説明を入れる)
- DarkMode
- (謎に、絵文字がゆっくり流れる背景アニメーションがあります)
成果物のURL
プロジェクト構成など
絵文字について
UnicodeコンソーシアムのFull Emoji Listの下記を参考に作成
下記の記事が絵文字の勉強になりました🙇♂️
力技で実装していく!💪
(生成AI時代なのに、力技で実装しています。まったく参考になりませんのでご了承ください。🙇♂️)
linderaというRust製の日本語形態素解析器を使ってみたかったので、
一部ロジックはRust(Wasm)で実装していきます。
まず、翻訳のデータを作成。
UnicodeコンソーシアムのFull Emoji ListのCLDR Short Nameを日本語訳し、Jsonのstring形式にする
ub fn get_json() -> &'static str { r#"[
{"cd":"U+1F600","nm":"grinning face","jp":"ニヤニヤ顔"},
{"cd":"U+1F603","nm":"grinning face with big eyes","jp":"大きな目のニヤニヤ顔"},
//略
]"#
}
次に。置換する関数を作成。
replace_emoji_with_name 関数
文字列、language、explainフラグを受け取り、絵文字をShortNameに置き換えた新しい文字列を返す。
すべての文字がUnicode絵文字の範囲(U+1F000からU+1F9FF)内にあるかどうかを確認し、
もしすべての文字が絵文字の範囲内であれば、単体の絵文字として扱う。🐈
g.chars().count() > 1:g が複数の文字を含むかどうかを確認し、🐈⬛
複数の文字を含む場合、最初の文字が絵文字の範囲内にあるかどうかを確認。
最初の文字が絵文字の範囲内であれば、合体絵文字として扱う。
上記外はそのまま文字列として扱う。
get_short_name 関数
絵文字文字列、language、explainフラグを受け取り、ShortNameを返す。
format_emoji_to_unicode関数でemojiをUnicode形式の文字列に変換します(例: "U+1F600")。
JSONデータから絵文字情報を読み込み、Unicodeコードが一致するEmojiRowをフィルタリングする。
languageに応じて、英名、日本語名を取得する。
explain フラグが true の場合、絵文字直後に説明を追加する(例: "😀(grinning face)")。
explain フラグが false の場合、説明のみを返す(例: "(grinning face)")。
//略
#[wasm_bindgen]
pub fn replace_emoji_with_name(text: &str,language: u32,explain: bool) -> String {
text.graphemes(true)
.map(|g| {
if g.chars().all(|c| (0x1F000..=0x1F9FF).contains(&(c as u32))) {
//単体絵文字
get_short_name(g, language,explain)
} else {
if g.chars().count() > 1 {
if let Some(c) = g.chars().next() {
if (0x1F000..=0x1F9FF).contains(&(c as u32)) {
//合体絵文字
get_short_name(g, language,explain)
} else { g.to_string() }
} else { g.to_string() }
} else { g.to_string() }
}
})
.collect()
}
/// emoji_unicodeに紐づくshort_nameにして返します(explainの時は絵文字直後に説明を入れる)
fn get_short_name(emoji :&str,language: u32,explain: bool) -> String {
let mut result = String::new();
let unicode = format_emoji_to_unicode(emoji);
let emoji_rows: Vec<EmojiRow> = from_str(get_json()).unwrap();
let objs = emoji_rows.iter()
.filter(|item| item.cd.as_str() == unicode);
for obj in objs {
if language == 0 {
result= obj.clone().nm;
}
if language == 1 {
result= obj.clone().jp;
}
break;
}
if explain {
let mut result_explain = String::new();
result_explain.push_str(emoji);
result_explain.push_str(&* format!("(*{}*)",result));
result_explain
}
else {
format!("(*{}*)",result)
}
}
/// emojiをunicodeにformatして返します
fn format_emoji_to_unicode(emoji :&str) -> String {
let mut unicode = String::new();
let mut i = 0;
for c in emoji.chars()
{
if i>0 {unicode.push_str(" ")};
unicode.push_str(&format!("U+{:X}", c as u32));
i = i + 1;
}
unicode
}
//略
replace_name_with_emoji 関数
文字列、explainフラグを受け取り、テキスト内の単語を絵文字に置き換える。
関数は、Tokenizerを使用してテキストを形態素解析し、各トークンをget_emoji関数に渡して絵文字に変換する。
get_emoji 関数
文字列、explainフラグを受け取り、与えられた単語に対応する絵文字を検索。
関数は、EmojiRowのリストをループし、英名または日本名がtextと一致する行を探し、
一致する行が見つかった場合、format_unicode_to_emoji関数でUnicodeコードを絵文字に変換し(例:"U+1F600")、
explainフラグに応じて元の単語を追加。
一致する絵文字が見つからない場合、元の単語がそのまま返す。
//略
#[wasm_bindgen]
pub fn replace_name_with_emoji(text: &str,explain: bool) -> String {
let mut result = String::new();
let dictionary = DictionaryConfig {
kind: Some(DictionaryKind::IPADIC),
path: None,
};
let config = TokenizerConfig {
dictionary,
user_dictionary: None,
mode: Mode::Normal,
};
let tokenizer = Tokenizer::from_config(config).unwrap();
let tokens = tokenizer.tokenize(text).unwrap();
for token in tokens {
result.push_str(&*get_emoji(token.text,explain));
}
result
}
/// short_name(類似名含む名詞単位)に紐づくemojiにして返します
fn get_emoji(text: &str,explain: bool) -> String {
let mut result = String::new();
let emoji_rows: Vec<EmojiRow> = from_str(get_json()).unwrap();
for row in emoji_rows {
// short_name
if row.nm == text {
if explain { result.push_str(text); }
result.push_str(&*format_unicode_to_emoji(&*row.cd));
break;
}
// short_name_jp
if row.jp == text {
if explain { result.push_str(text); }
result.push_str(&*format_unicode_to_emoji(&*row.cd));
break;
}
}
if result.is_empty() {
result.push_str(text);
}
result
}
/// unicodeをemojiにformatして返します
fn format_unicode_to_emoji(unicode: &str) -> String {
let result
= unicode.split_whitespace().map(|code| {
if let Some(stripped) = code.strip_prefix("U+") {
if let Ok(hex) = u32::from_str_radix(stripped, 16) {
char::from_u32(hex).unwrap_or_default().to_string()
} else {
code.to_string()
}
} else {
code.to_string()
}
})
.collect::<String>();
result
}
//略
ソース
まとめ
絵文字翻訳ツールを作ってみたが、お披露目するところがなかったので、
クソアプリとして供養いたしました。😊
自分の作ってみたいものを、
力技や自分の好きなように実装するのは、とっても楽しい!💪