かわみのメモ帳

趣味に関するメモを書いていきます。

Javaで文字列から絵文字を取り除く方法について

おはようございます、かわみです。
本当にメモ帳的な更新となりますがご了承ください。

さて、趣味でジャバジャバしてたらとあるところで躓きました。
Javaにおける絵文字の正規表現です。
とりあえず動く実装方法が見たい方は一番下までスクロールしてください。

絵文字の正規表現

絵文字の正規表現について調べていると、パオの民のこのようなトゥートを発見しました。

mstdn.jp

パオSNSでは、正規表現を使ってタイムラインのトゥートを抽出できるのでこのようなトゥートが投稿されていますが、
絵文字を含むトゥートを抽出する正規表現として

^[^\uD800-\uDFFF]*$

と書いてありますが、(Javaで動くような表現だと、)絵文字1文字はこのように表されますよね。

[\\uD800-\\uDFFF]

Javaで文字列から絵文字を取り除く方法

文字列から絵文字を取り除く方法は、単純にコードを書けば、

String str = "あいうえお😀かきくけこ";  
System.out.println(str.replaceAll("[\\uD800-\\uDFFF]", ""));

となり、"あいうえおかきくけこ"と出力されるはずです。
しかしながら現実は残酷。少なくとも私の環境ではこのように出力されました。

あいうえお?かきくけこ

上記の楽しそうな顔は'?'になってしまったようです。感情を失ってしまって無になっている。
皆さんはもちろんString.replaceAllメソッドの実装をご存じかと思いますが、
どうやら今回のケース、MatcherクラスのreplaceAllメソッドの実装と噛み合っていないようでした。
細かいことは各自その実装をご覧いただくこととして、他に賢い方法はないかと。

String.replaceAllメソッドの利用で'?'には置換できているわけなので、比較はできているのです。
したがって、「文字単位で比較した際に一致しなかった文字だけを集めれば結果的にそれを除外できたことになるのでは?」と考えました。
そんな頭の悪い実装しか思い浮かばない私の出したその場しのぎ的な答えがこれです。

String str ="あいうえお😀かきくけこ";  
StringBuilder sb = new StringBuilder();
for (int i = 0; i < str.length(); i++) {
    char c = str.charAt(i);
    if (!String.valueOf(c).matches("[\\uD800-\\uDFFF]")) { 
        sb.append(c);
    }
}
String replaced = sb.toString();
System.out.println(str + " -> " + replaced);

そして出力結果はどうなるのかと申しますと、

あいうえお😀かきくけこ -> あいうえおかきくけこ

となってくれました。ちゃんと動いた。
ただ、もう少し簡単に実現する方法がありそうな気がするので、
皆さんも随時頭の良い方の記事を探しましょう。