BlueskyのAPIを使うにあたって、文字列のバイト数を計算する必要があるケースがあったので Power Automate のクラウドフローでできないかなと考えてみました。
計算結果のチェックには以下のサイトを使っています。
UTF-8 string length & byte counter
例えば日本語や絵文字を含むような文字列を入れると、何文字で何バイトの文字列なのかを計算してくれます。
文字のバイト数?
例えばUTF-8で単純な英数字+記号であれば、基本は1文字=1バイト で表現されます。ですので、 Hello World
はスペースを含めて11文字=11バイトの文字列です。
一方で、良く知られている例ではひらがなや一部を除いて漢字は1文字=3バイトで表現されます。
ちょっと厄介なのが絵文字(Emojis)です。これは絵文字の種類によって何バイトなのかが変わります。
例えば👍は4バイトですが、👩👩👦はなんと1文字に見えて18バイト!!
このように、絵文字は何を使うかによって単純に「絵文字だから4バイト」みたいな対応にはなっていません。
(参考: 絵文字👨🏻🦱は何文字としてカウントする?関連する文字コードの仕様を詳しく調べてみた #文字コード - Qiita)
このあたりを踏まえて、じゃあ与えられた文字列が全部で何バイトなのか を計算するのが今回の課題です。
考え方
マルチバイト文字を含めてどうやって文字列のバイト数を計算するのか。そのカギは encodeUriComponent()
関数です。
式関数のリファレンス ガイド - Azure Logic Apps | Microsoft Learn
encodeUriComponent関数を使うと、英数字と一部の記号を除き、文字列を16進数のバイト表記してくれます。
例えば encodeUriComponent('あ')
は %E3%81%82
という16進数のペア × 3つ が結果として返されます。まさにこの %XX
が1バイトを表していて、ひらがなが3バイトであることとも一致します。
先ほどの絵文字、👍と👩👩👦ですが、それぞれ以下の結果が得られます。
- 👍 -->
%F0%9F%91%8D
(%XX が4つ = 4バイト) - 👩👩👦 -->
%F0%9F%91%A9%E2%80%8D%F0%9F%91%A9%E2%80%8D%F0%9F%91%A6
(%XX が18個 = 18バイト)
もっと単純には、マルチバイト文字のみに限れば、encodeUriComponent で変換した後の "%" の数 = バイト数 ということがわかります。
%の数をかぞえる
Power Automateで特定の文字の出現数を数えるには split()
関数が使えます。例えば 123%E3%81%82
は% を3つ含んでいますが、split('123%E3%81%82')
の結果は ['123','E3','81','82']
となり、split関数の結果得られた配列の長さ -1 が%の出現数に一致します。
結局、%の数をかぞえる数式はクラウドフローでは以下のようになります。
sub(length(split( <%を含む文字列> ,'%')),1)
マルチバイトのみで構成される文字列であれば、上記の数式でバイト数が計算できます。
シングルバイトとマルチバイトが混在する場合の表現
シングルバイト文字 (英数字) とマルチバイト文字が混在する場合でも encodeUriComponentを使う点と、%の数を数えるのは同じです。
混在した場合でも、encodeUriComponentした後の文字列に含まれる%の数がマルチバイト文字列のバイト数になります。
それ以外のシングルバイト文字のバイト数(=文字数)は、%XXの部分を除いた数なので、全体の文字数から 3 x %の数 を引けばいいことが分かります。
結局、混在した場合のPower Automateでの数式は以下のようになります。
sub(length(<encodeUri後の文字列>),mul(sub(length(split(<encodeUri後の文字列>,'%')),1),2))
この表現はシングルバイトのみの場合でも利用可能で、絵文字などの4以上のバイト文字が含まれていても使える一般的な表記となります。
まとめ
結局、特定の文字列をInputText
のような名前の変数で定義した場合には、encodeUIriComponentも含めて以下のように数式を書くことで、入力された文字列のバイト数がカウントできることがわかりました。
sub( length( encodeUriComponent(variables('InputText')) ), mul( sub( length( split(encodeUriComponent(variables('InputText')),'%') ), 1), 2) )
参考
JavaScript文字列のバイト数を数える - encodeURIComponent版 #JavaScript - Qiita