Contents
はじめに
私が受講しているプログラミング学習スクールRareTECHでNgramを実装してみようという課題があり、Swiftで挑戦したところ見事に撃沈したので調べて実装してみました。
以下のバージョンで実行しています。
- Xcode: Version 13.2.1 (13C100)
- Swift: 5.5.2
Ngramとは
コトバンクでは以下のように定義されています。
任意の文字列や文書を連続したn個の文字で分割するテキスト分割方法.特に,nが1の場合をユニグラム(uni-gram),2の場合をバイグラム(bi-gram),3の場合をトライグラム(tri-gram)と呼ぶ.最初の分割後は1文字ずつ移動して順次分割を行う.
イマイチピンと来ないので例を用いて説明します。
Ngramの例
N = 1のとき
"吾", "輩", "は", "猫", "で", "あ", "る"
1文字ずつ区切られます。
N = 2のとき
"吾輩", "輩は", "は猫", "猫で", "であ", "ある"
区切りの先頭の文字を1文字ずつずらしながら、2文字ずつ区切っていきます。
N = 3のとき
"吾輩は", "輩は猫", "は猫で", "猫であ", "である"
N = 2と同様ですが今度は3文字ずつ区切っています。
実装
処理のフローを考えてから実装に入ります。
処理のフロー
-
- 分割する文字列(input)と何文字毎に分割するかの整数値(n)を受け取る。
- 取り出した文字列を格納するための配列(sentence)を宣言する。
- inputの先頭のindexを定義しておく。
- inputの文字数 - n 回ループする(最後の要素のindexは文字数-nにしないと範囲外にはみ出てしまう)
- 取り出す文字の先頭の文字のindexを定義。
- 取り出す文字の末尾の文字+1のindexを定義。
- 指定した範囲で文字列を取り出す。
- 取り出した文字列をsentenceに追加する。
- sentenceを返却or出力する。
実際のコード
実装のポイント
分割する文字のindexとnの関係について考えてみるとわかりやすいです。
吾[0] 輩[1] は[2] 猫[3] で[4] あ[5] る[6]
[]内は要素のindexです。
indexの数は文字数 -1 になります。
n = 2のときは最後の「ある」の先頭の文字の「あ」のindexは5であり、文字数 7 - n(2)になります。
n = 3のときは最後の「である」の先頭の文字の「で」のindexは4であり、文字数 7 - n(3)になります。
Swiftの文字列操作に苦戦しました。
文字列操作については別記事にまとめたいと思います。
おわりに
私の理解が甘く、間違った情報を記載している部分があるかもしれません。
また上記の実装よりもよりよい実装があるかと思います。
誤りなどありましたらご指摘いただけましたら幸いです。
参考資料
Swift 実践入門 増補改訂第 3 版
https://kotobank.jp/word/N%E3%82%B0%E3%83%A9%E3%83%A0-1702302
https://chusotsu-program.com/swift-string-slice/