強火で進め

このブログではプログラム関連の記事を中心に書いてます。

iOS向けにXCFrameworkを作成し、署名する手順

この記事ではXCFrameworkを作成し、署名(コード署名)を行う手順を解説します。 解説前にまず、記事内に出てくる用語の解説を書いておきます。知らない用語が出てきたらここに戻ってきて確認して下さい。

用語解説

Archive

配布やストアに公開時に必要な実行可能ファイル、アセット、メタデータなどのリソースをBundle化したもの。

Bundle(バンドル)

標準化された階層構造を持つディレクトリにリソースをまとめたもの。通常は1つのファイルの様に扱われるが右クリックメニューから「パッケージの内容を表示」を選択するとディレクトリに含まれた内容が確認できる。

参考情報:Placing Content in a Bundle | Apple Developer Documentation

Framework

Dynamic shared library(動的共有ライブラリ)やStatic Library(静的ライブラリ)、アセット、メタデータなどをBundle化したもの。

Dynamic shared library(動的共有ライブラリ)

実行時にアプリから利用する形式のライブラリ。複数のアプリから同時に利用する事が可能である為、メモリが節約できるという利点が有る。また、必要になった時点でロードされる為に起動時に必要にメモリ量が抑えられるなどの利点が有ります。

Static Library(静的ライブラリ)

アプリのビルド時にアプリ内に取り込まれる形式のライブラリ。

署名

そのファイルやXCFrameworkに対して、以下の事を保証する仕組み。

  • 署名された時点から変更が行われていない
  • 制作者は署名した人である

制作者が署名処理を行う事で署名済みのファイルやXCFrameworkを作成する事ができます。

XCFrameworkを作成

まずはXcodeで普通にiOSのFrameworkを作成します。

※Frameworkの作成方法については別途検索して下さい。

Frameworkを作成する時にはXcodeプロジェクトのBuild Settingsタブで以下ものを検索して設定を変更して下さい。

  • Build Libraries for Distributionã‚’Yes
  • Skip Installã‚’No

FrameworkのXcodeプロジェクトの準備できたらターミナルを開き、.xcodeprojファイルがあるディレクトリへ移動します。

ディレクトリで以下のコマンドを実行するとiOS環境向けのarchiveが作成されます。

例) TestFrameworkというプロジェクトの場合

xcodebuild archive \
    -project TestFramework.xcodeproj \
    -scheme TestFramework \
    -destination "generic/platform=iOS" \
    -archivePath "archives/TestFramework-iOS"

-projectでXcodeのプロジェクトのパスを指定、-archivePathでarchiveの生成先のパスを指定します。

続いてiOSシミュレータ環境向けに作成します。コマンドはこちら。

xcodebuild archive \
    -project TestFramework.xcodeproj \
    -scheme TestFramework \
    -destination "generic/platform=iOS Simulator" \
    -archivePath "archives/TestFramework-iOS_Simulator"

これでiOS向けとiOSシミュレータ向けのarchiveが作成できました。

次に以下のコマンドで2つのarchiveからXCFrameworkを作成します。

xcodebuild -create-xcframework \
    -archive archives/TestFramework-iOS.xcarchive -framework TestFramework.framework \
    -archive archives/TestFramework-iOS_Simulator.xcarchive -framework TestFramework.framework \
    -output xcframeworks/TestFramework.xcframework

-archiveで指定したarchiveの中の含まれているどのFrameworkを使用するかを-frameworkで指定します。-outputで指定したパスにXCFrameworkが生成されます。

ここでNo 'swiftinterface' files found within '(ここにTestFramework.swiftmoduleのパス)'というエラーが表示された時にはFramework作成時の設定として記述したBuild Libraries for DistributionをYesが行われているか確認して下さい。

error: the path does not point to a valid framework: (ここにTestFramework.frameworkのパス)というエラーが表示された時にはSkip InstallをNoが行われているか確認して下さい。

もし、Frameworkではなく、.aファイル(Static Libraryファイル)からXCFrameworkを作成したい場合には-frameworkの代わりに-libraryで.aファイルのパス、-headersでヘッダファイルのディレクトリを指定します。

(コマンド例)

xcodebuild -create-xcframework
    -library products/iOS/usr/local/lib/libMyLibrary.a -headers products/iOS/usr/local/include
    -library products/iOS_Simulator/usr/local/lib/libMyLibrary.a -headers products/iOS/usr/local/include
    -output xcframeworks/MyLibrary.xcframework

署名

署名はApple Developer ProgramのID、もしくは自己署名証明書で行えます。

ここではApple Developer ProgramのIDで署名する方法を解説します。

Apple Distributionをまだ作成していない場合には作成が必要です。

※Apple Distributionの作成方法については別途検索して下さい。

Apple Distributionを作成し、Keychain(「キーチェーンアクセス」アプリ)に追加済みで有れば以下の様な証明書が見つかるはずです。

この「Apple Distribution: 」で始まる行の文字列は署名を行う時に必要なのでメモしておいて下さい。

署名を行う

ターミナルで以下のコマンドを実行するとXCFrameworkに署名が行われます。

codesign \
    --timestamp \
    -s "Apple Distribution: XXXXX (YYYYYYYYYY)" 
    xcframeworks/TestFramework.xcframework

--timestampで署名時刻の認証を要求します。-sでAppple Distributionの情報を記載します。先ほどメモしていたApple Distribution:から始まる文字列を記載して下さい。最後に署名を行うXCFrameworkのパスを指定します。

これでXCFrameworkの作成と署名の作業が終わりました。

署名状況の確認

まず簡単な確認方法としてはXCFrameworkの中に_CodeSignatureというディレクトリが存在するかで確認できます。このディレクトリが存在する場合には署名済みです。

XcodeプロジェクトにXCFrameworkを追加済みの場合にはXCFrameworkを選択した状態で右側に有るインスペクターでファイルタブを見ると確認できます。ここに有るSignatureというブロックにStatus Verification succeededという記載が有ると署名に成功しています。

関連情報

developer.apple.com

glTFastで「ShaderMissing;glTF/PbrMetallicRoughness」というエラーが発生

Unity glTFastで.gltfや.glbファイルを読み込むWebGLアプリを作った所、以下のエラーが発生しました。

ShaderMissing;glTF/PbrMetallicRoughness

glTF/PbrMetallicRoughnessというShaderが見つからないというエラーです。 アプリ内でこのShaderを使って無い為、ビルド時に含まれていなかったのかな?と予想。

gltFastで使っているShaderはパッケージフォルダ内のRuntime/Shaderが該当しそうですね。

フォルダを右クリックし、メニューの中からShow in Explorerを選択。

今回はBuilt-Inパイプラインを使っているので(※1)、AssetsフォルダにResourcesフォルダを作成し、そこにBuilt-Inフォルダをコピー(※2)。

※1 URPやHDRPを使っている人はそれに合わせたものを選択しましょう。

※2 何故かエクスプローラーからUnityエディタへのドラッグでは上手くコピー出来なかったのでエクスプローラー上でコピーしました。

これで無事にエラー無く、表示されました。

UnityでのAppleのPrivacy Manifestへの対応方法

Privacy Manifestとは?

Privacy Manifestとは2024年春から導入される予定のAppleの新しいプライバシー対策のアップデートです。

App Storeへの提出におけるプライバシー要件のアップデート - 最新ニュース - Apple Developer

このアップデートにより、フィンガープリントに利用できる情報にアクセスをするAPI(※)を使用する場合にはPrivacy Manifestというファイルを作成し、そこでAPIを利用する理由を明示するというルールが導入されます。

※Appleはフィンガープリントの使用を禁止しています。ユーザのトラッキングにはフィンガープリントでは無く、広告識別子(IDFA)を使う必要が有ります。

Xcodeのメニューから File > New > File… と選択し、Resourceセクションに有るApp Privacyを選択するとPrivacyInfo.xcprivacyというファイルで空のPrivacy Manifestファイルが作成されます。

Unityでの対応方法

Unityでは以下のバージョンからPrivacy Manifestに対応しています。その為、Unityでの対応方法としては該当のバージョンへのバージョンアップになります。 それ以前のバージョンを使ってプロジェクトを作成している場合にはバージョンアップが必要に有ります。

Privacy Manifest ファイルが生成される様になったバージョン

Release NoteにはAdded Apple Privacy Manifest support.と記載されています。

系統 バージョン
Unity 2021.x系 Unity 2021.3.35f1(2024/2/8リリース)
Unity 2022.x系 Unity 2022.3.18f1(2024/1/20リリース)
Unity 2023.x系 Unity 2023.2.7f1(2024/1/23リリース)

※このバージョンで生成されるPrivacy Manifestファイルには「System boot time APIs - 35F9.1」の記載が抜けています。こちらについてはUnity 2023.2.13、2022.3.21、および 2021.3.36で修正予定とアナウンスされています。

「System boot time APIs - 35F9.1」の記載漏れが修正されているバージョン

Release NoteにはAdded missing privacy manifest entry for System Boot time API usage.と記載されています。

Unity 2023.2.13f1だけはFixed an issue by adding a missing privacy manifest entry for System Boot time API usage.と記載されています。

系統 バージョン
Unity 2021.x系 Unity 2021.3.36(2024/3/5リリース)
Unity 2022.x系 Unity 2022.3.21f1(2024/3/5リリース)
Unity 2023.x系 Unity 2023.2.13f1(2024/3/5リリース)

UnityにPrivacy Manifest向けの機能として追加される内容についてはこちらのページ(英語)を参照下さい。

重要な部分を引用しておきます。

[Available today] Unity Engine core Required Reason Privacy Manifest entries & related Documentation. See them here. This covers Unity Engine core’s internal usage of Required Reasons APIs.
[Available today] Documentation for C# methods that map to Required Reason APIs. If you use one of these, you will need to declare a Reason. See them here.
[Available today] Fixes to the Unity Engine core to comply with Required Reasons. We are updating the Engine to use fewer Required Reason APIs. This change is available in Unity 2021.3.34f1, 2022.3.16f1 and 2023.2.5f1 releases. This is an internal change, so it is not mentioned in the release notes. This change requires a Unity Editor update.
[Available soon] Solution to incorporate Privacy Manifests coming from Unity plugins, packages and your project. We expect this change to be available in Unity 2021.3.35f1, 2022.3.18f1 and 2023.2.7f1 releases. The release notes will state "Add Apple Privacy Manifest support". This change will require a Unity editor update.
[Work in progress] We will sign Unity Engine libraries within UnityFramework. We expect this change to be available in Unity 2021/2022/2023 forthcoming patch releases This change will require a Unity editor update.

(翻訳)

[本日公開】Unity Engineコア 必須理由 プライバシーマニフェストエントリ&関連ドキュメント。こちらをご覧ください。Unity Engine coreのRequired Reason APIの内部的な使用方法をカバーしています。
[本日公開】Required Reason APIに対応するC#メソッドのドキュメントです。これらのいずれかを使用する場合は、Reasonを宣言する必要があります。こちらを参照してください。
[本日公開】Required Reasonに対応するためのUnity Engineコアの修正。より少ないRequired Reason APIを使用するようにエンジンを更新しています。この変更はUnity 2021.3.34f1、2022.3.16f1、2023.2.5f1で利用可能です。これは内部的な変更であるため、リリースノートには記載されていません。この変更にはUnity Editorのアップデートが必要です。
[近日公開予定] Unityプラグイン、パッケージ、プロジェクトからのプライバシーマニフェストを取り込むためのソリューションです。この変更はUnity 2021.3.35f1、2022.3.18f1、2023.2.7f1リリースで利用可能になる予定です。リリースノートには「Add Apple Privacy Manifest support」と記載されます。この変更にはUnityエディタのアップデートが必要です。
[作業中] UnityFramework内のUnity Engineライブラリに署名します。この変更は、Unity 2021/2022/2023の今後のパッチリリースで利用可能になることを期待しています。

現時点ではここに記載されている様にUnityエディタでは「Privacy Manifestファイルについて扱える様になった」という部分まで対応済みで、署名の作業については作業中です。

Unity Engine コア ライブラリは署名する必要無くなった様です。

また、Unity公式ドキュメントのここに Privacy Manifest についての情報が追加されているので目を通しておいた方が良いでしょう。

Unity が生成する Privacy Manifest ファイルの内容を確認

UnityでXcodeプロジェクトを生成するとPrivacyInfo.xcprivacyが含まれたプロジェクトが作成されます。ファイルをXcode上で開くと以下の様に表示されます。

ファイルを直接開いた場合には以下の様になります。

<?xml version="1.0" encoding="utf-8"?>
<plist version="1.0">
  <dict>
    <key>NSPrivacyAccessedAPITypes</key>
    <array>
      <dict>
        <key>NSPrivacyAccessedAPIType</key>
        <string>NSPrivacyAccessedAPICategoryDiskSpace</string>
        <key>NSPrivacyAccessedAPITypeReasons</key>
        <array>
          <string>E174.1</string>
        </array>
      </dict>
      <dict>
        <key>NSPrivacyAccessedAPIType</key>
        <string>NSPrivacyAccessedAPICategoryUserDefaults</string>
        <key>NSPrivacyAccessedAPITypeReasons</key>
        <array>
          <string>CA92.1</string>
        </array>
      </dict>
      <dict>
        <key>NSPrivacyAccessedAPIType</key>
        <string>NSPrivacyAccessedAPICategoryFileTimestamp</string>
        <key>NSPrivacyAccessedAPITypeReasons</key>
        <array>
          <string>0A2A.1</string>
          <string>C617.1</string>
        </array>
      </dict>
    </array>
    <key>NSPrivacyCollectedDataTypes</key>
    <array />
  </dict>
</plist>

ここで使われているパラメータの説明は以下のAppleの公式ドキュメントで確認できます。

Privacy manifest files | Apple Developer Documentation

※ドキュメントはトップページだけでは無く、Describing data use in privacy manifestsとDescribing use of required reason APIも確認しましょう。

主な部分について確認してみましょう。以下の部分に注目してみます。

      <dict>
        <key>NSPrivacyAccessedAPIType</key>
        <string>NSPrivacyAccessedAPICategoryDiskSpace</string>
        <key>NSPrivacyAccessedAPITypeReasons</key>
        <array>
          <string>E174.1</string>
        </array>
      </dict>

この部分ではdictの中にkeyとして、NSPrivacyAccessedAPIType。valueとしてstring(文字列)で「APIのカテゴリ」を記述するルールになっています。ここではNSPrivacyAccessedAPICategoryDiskSpaceが設定されています。Appleの公式ドキュメントで確認するとこれは「Disk space APIs」と記載されており、「使用可能なディスク容量にアクセスするAPI」のカテゴリだと確認できます。

次にkeyとして、NSPrivacyAccessedAPITypeReasonsが有ります。このkeyに対応するvalueとしては「アプリが API を使用する理由を示す文字列」を配列(array)の中にstring(文字列)で記述します。ここではE174.1が記述されています。E174.1の説明文は「ファイルを書き込むのに十分なストレージの空き容量が有るか確認する為」と書かれています。

話をまとめると使用するAPIについて「カテゴリ」と「そのAPIを使用する理由」を記述する必要が有り、解説した部分では以下の内容を記述しています。

  • カテゴリ :Disk space APIs
  • 理由:ファイルを書き込むのに十分なストレージの空き容量が有るかを確認する為

なお、理由の部分は配列なので1つでも複数でも設定可能です。実際、以下の様に複数設定している箇所も有ります。

        <key>NSPrivacyAccessedAPIType</key>
        <string>NSPrivacyAccessedAPICategoryFileTimestamp</string>
        <key>NSPrivacyAccessedAPITypeReasons</key>
        <array>
          <string>0A2A.1</string>
          <string>C617.1</string>
        </array>

ドキュメントに記載されている内容と生成されるPrivacy manifestファイルの内容に差が有る

Unityのドキュメントを確認するとUnity Engine内で使用しているAPIに関するPrivacy manifest(「カテゴリ」と「理由」)が確認できます。

この情報を確認すると「System boot time APIs - 35F9.1」についての部分が生成されたPrivacyInfo.xcprivacyには含まれてない事が確認できます。

こちらについてはフォーラムの投稿によるとドキュメントが正しく、PrivacyInfo.xcprivacyの記述が間違ってるようです。まぁ、直ぐに修正されるでしょうが待てない場合は手動で追加しましょう。

Privacy Manifestファイルの自作例

例としてここではUnity向けにiOSのPluginを自作したというシチュエーションを想定します。

このPluginの中では「UIDocumentPickerViewController経由でファイルのタイムスタンプにアクセスする」という事があります。この場合にはどの様な Privacy Manifest ファイルを作成するのかを考えます。

まずはファイルのタイムスタンプに関わる事なのでNSPrivacyAccessedAPITypeに設定するのはNSPrivacyAccessedAPICategoryFileTimestampになります。

次にNSPrivacyAccessedAPITypeReasonsで設定する理由について考えます。

確認すべきはこちらのドキュメントです。 NSPrivacyAccessedAPICategoryFileTimestamp(File timestamp APIs)には以下の理由が選択可能です。

値 説明
DDA9.1 デバイスを使用している人にファイルのタイムスタンプを表示する。この理由でアクセスされた情報はデバイス外に送信できない。
C617.1 アプリ コンテナ、アプリ グループ コンテナ、またはアプリの CloudKit コンテナ内のファイルのタイムスタンプ、サイズ、またはその他のメタデータにアクセス。
3B52.1 ドキュメント ピッカー ビュー コントローラー(UIDocumentPickerViewController)を使用するなど、ユーザーが特別にアクセスを許可したファイルまたはディレクトリのタイムスタンプ、サイズ、またはその他のメタデータにアクセスする。
0A2A.1 サードパーティ SDK がアプリが使用するファイル タイムスタンプ API のラッパー関数を提供しており、アプリがラッパー関数を呼び出すときにのみファイル タイムスタンプ API にアクセスする。

3B52.1が該当しそうですね。これを設定します。

この情報をまとめるとファイルの内容は以下の様になります。

<?xml version="1.0" encoding="utf-8"?>
<plist version="1.0">
  <dict>
    <key>NSPrivacyAccessedAPITypes</key>
    <array>
      <dict>
        <key>NSPrivacyAccessedAPIType</key>
        <string>NSPrivacyAccessedAPICategoryFileTimestamp</string>
        <key>NSPrivacyAccessedAPITypeReasons</key>
        <array>
          <string>3B52.1</string>
        </array>
      </dict>
    </array>
  </dict>
</plist>

これをPrivacyInfo.xcprivacyというファイル名(※)で保存し、Assets/Plugins/iOSという構造のフォルダを作成し、そこに配置します。

※拡張子が.xcprivacyならPrivacy Manifestファイルと判定されるので実際にはPrivacyInfoの部分はPlugin名など区別が付きやすい名前を使った方が良いでしょう。保存するフォルダについてもAssets/Pluginsを使う事も可能です。

Xcodeプロジェクト内のPrivacyInfo.xcprivacyを確認すると以下の様にきちんと追加されている事が確認できます。

Item2の所に追加されるのが綺麗では有りますが、これでも記述ルール的にはOKなのかな?

補足

現状、Xcode(Version 15.2)で「Generate Privacy Report」を実行した時に空白の(何も記述されていない)PDFが生成されます。 FlutterのGithubのissueでも同じ症状が出ているとの記載が有る為、現状はこの挙動になる様です。

エラー「Tensor data cannot be read from, use .MakeReadable() to allow reading from tensor.」の修正方法

GitHubで配布されいてるUnity Sentisを使ったプロジェクトを実行してみた所、以下の様なエラーが発生しました。

InvalidOperationException: Tensor data cannot be read from, use .MakeReadable() to allow reading from tensor.

調べてみると原因はバージョンアップ時の仕様変更みたいです。

参考情報 docs.unity3d.com

出力されたテンソルを使う前にoutputTensor.MakeReadable()の様にMakeReadable()を呼ぶ事で無事、動作しました。

「AI Text Classifier」が使用できなくなりました

OpenAIのサイトでは「AI Text Classifier」というAIが生成したテキストかどうかを判定するツールを公開していました。

OpenAI、AIが書いた文章かどうか判別するツール - PC Watch https://pc.watch.impress.co.jp/docs/news/1474899.html

しかし、2023/7/20に精度が低いという判断から公開が停止された様です。

情報元 openai.com

AI(ChatGPTなど)について

AIは便利?

ChatGPT、便利だと言う人も使えないという人も居ます。

実際に使ってみると自分が想定している以上の回答が貰える時も全然的外れな回答がされる時も有ります。

しかし、これは質問の仕方を工夫する事で改善される事も多いです。この辺りはインターネットの検索ワードと同じ様な印象を持っています。例えばインターネットで何かについての說明を調べたい時には「◯◯とは」を検索ワードに「とは」付けて検索するとそのワードについての解説ページが見つかりやすくなるというテクニックが有ります。同じ様にChatGPTに適した質問文にすると良い答えが返ってくる事が多いです。

「ChatGPT プロンプト テクニック」などの検索ワードで検索すると良い質問方法について解説したページがいくつも見つかるかと思います。また、ChatGPT-4でかなり能力が上がっているのでChatGPT-3.5の場合には正しい結果を返してくれないような質問をしてもChatGPT-4では正しい回答をしてくれたり、改善されています。なのでそちらを活用するのも良いです。

なお、ChatGPT-4は公式サイトでは有料のサブスクリプションに加入する必要が有ります。ChatGPT-4を活用して構築されているマイクロソフトのBingなどは無料で使えるのでそちらで試すのも良いでしょう。

japan.cnet.com

AIは危険?

以前、AIツールはリスクが有るとのニュースが有りました。

toyokeizai.net

こちらについては確かに危険性は有るかもだけど上手く折り合いが付けれる結果になると良いなぁという感想を持ちました。

これもインターネットと同じかな?と思っています。「インターネットは危険」と言われると「そうだそうだ」という意見も「そうじゃないでしょ?安全でしょ?」という両方の意見が出てくると思います。

しかし、実態としては危険と思っている人も危険と思いながらもインターネットを使っている人も多いのでは無いでしょうか?そういう人は「変なサイトに行かない」「変なメールに付いているURLは開かない」など、インターネットは危険だからと注意をしながら活用しているかと思います。

また、場所によってどれくらい使って良いかを判断するの大切だと思います。今でも原子力発電所の制御部分は変な攻撃を受けない様にインターネットには接続していないでしょう。しかし、ほとんどの会社で使うPCはセキュリティ面には気を付けた対策をしている前提でインターネットを活用しているでしょう。AIの活用についてもこの様に場面場面に有った安全に配慮する前提はもちろん大切かと思います。

今行われている議論がAIに対しても同様に「危険だから全部無しで」では無く、危険な部分を避けながら正しく活用できる未来になれば良いなと思っています。

ChatGPTのトークン(token)について検証

Tokenizer(公式のトークン数確認ツール)を使ってどんな文字だと何トークンに何かを検証。

※「GPT-3」の設定で検証。将来、「GPT-4」の設定など他のものだとルールが変わる可能性が有ります。
※このルールと外れる様なパターンを見つけた方はコメント欄に書いて貰えると嬉しいです。

ツールの解説

このツールでは文字の背景色が同じ色の範囲が1トークンを表しています。 Tokens にトークン数、 Characters に文字数が表示されます。

英語

「英語」は1単語、基本1トークン。

「red」「three」で検証。

文字数が多いとトークン数が増える事が有る。おおよそ4文字で1トークンくらい。

5文字以上だと常に2トークンというわけでは無く、文字数が多くても1トークンな単語も有る。

一般的な英語辞書に載っている中で一番長い単語と言われている「Pneumonoultramicroscopicsilicovolcanoconiosis」は45文字で15トークン。

日本語

ひらがな

「ひらがな」は1文字、1~2トークン。

(全角)カタカナ

「カタカナ」は1文字、基本1トークン。

長文を入れてみると文字数よりトークン数が少ないという結果が発生。

よく見ると「ーク」の所が1トークン扱いになっています。

長音記号とその後の文字とセットでで1トークンという法則が有りそうです。

「ッ」などの小さい文字(捨て仮名)もその後の文字とセットで1トークン。

半角カタカナ

「半角カタカナ」は1文字、3トークン。

「ア」は3トークン。
※UTF-8で3バイト。

「゙」(濁点)や「゚」(半濁点)もそれぞれ3トークン。 ※UTF-8でそれぞれ3バイト。

全角カタカナの時と違い、「ーク」や「ック」の場合に半分のトークン数になるという事は無い。

という事で、特別な理由が無い限りは全角カタカナを使った方が良いでしょう。

漢字

「漢字」は1文字、基本2~3トークン(レア漢字だとそれ以上の場合も)。

「今日」や「都道府県」は「文字数x2=トークン数」ですが、それ以外は「文字数x3=トークン数」になっています。

「𠮷」(つちよし)や「𩸽」(ほっけ)だと4トークン。2文字と認識されているのも気になります。

※UTF-8で4バイト。

渡辺の「辺」の異体字である「邊󠄄」だと7トークンにもなる。3文字と認識されているのも気になります。

※ちなみにUTF-8で処理しようとするとIVSなので7バイト。

絵文字

「絵文字」は1文字、基本2トークン。

旧絵文字の「☺」は2トークン。

カラー絵文字の「😀」も2トークン。なぜか2文字と認識。

サロゲートペアを使っている「🧑🏻」(明るい肌色の顔)※参考ページの絵文字だと10トークンになる事も。コードポイントは1F9D1 1F3FB。UTF-8で8バイト。

「👨‍👩‍👦」(家族: 男性、女性、男の子)※参考ページの場合も10トークン。コードポイントは1F468 200D 1F469 200D 1F466。UTF-8で18バイト。

日本語の文章と英語の文章の比較

同じ内容でも日本語の場合は19トークン、英語の場合は9トークンになりました。英文の最後のピリオドは省略しても問題無い事が多いのでそこまで攻めると8トークンまで減らす事も可能ですね。中々、大きな違いです。

ChatGPT で長文の文章を使いたい時や ChatGPT API を使う時のコストを抑える事を考えると英語で問題無い場面では英語を使う方が良さそうです。

公式の情報

Tokenizerのページの注記。

経験則として、一般的な英語のテキストでは、1トークンは~4文字のテキストに相当します。これはおよそ1単語の3/4に相当します(つまり100トークン~=75単語)。

ヘルプページ「トークンとは何ですか?またその数え方は?」。

1 トークン ~= 英語の 4 文字
1 トークン ~= ¾ ワード
100 トークン ~= 75 ワード

また

1-2 文 ~= 30 トークン
1 段落 ~= 100 トークン
1,500 ワード ~= 2048 トークン

ウェイン・グレツキーの名言 "You miss 100% of the shots you don't take" には 11 個のトークンが含まれています。
OpenAI の憲章には 476 個のトークンが含まれています。
米国独立宣言の謄本には1,695 個のトークンが含まれています