【Swift】Yahooのテキスト解析APIを使用して五十音順ソートを実装する
おはこんばんにちは、しょーです。
以前とある入社試験で、漢字にルビを取得して表示する簡単なアプリの作成をしたのですが、そのAPIをKaraokeyに使えるなぁと思ったので実行することに。
今回やることは
テキスト解析APIを叩いて、漢字を含んだリストをあいうえを順に並べる
です。
さてお茶でも飲みながら行ってみよう(ZONE飲んでる)。
使用するAPI
今回使用するAPIはYahooディベロッパーネットワークから出ているルビ振りAPIです。
https://developer.yahoo.co.jp/webapi/jlp/furigana/v1/furigana.html
目的
テキスト解析APIを叩いて、漢字を含んだリストをあいうえを順に並べる。
したはもう完成図ですが、A-Zあいうえお順に並び替えます。
公式サイトで使用するアプリケーションの登録をする
こちらに必要事項を入力していきます。
そうするとアプリケーションIDが発行されるので、パラメーターに変換したいテキストと一緒に付与してリクエストを送ってくれればおkです。
リクエストを作成する
リクエストを作成していくぞー。
大体レスポンスはJSONだろー、いつも使ってるテンプレートでっと、、、
しかししょーはまだ気付いていなかった。
レスポンスはJSONではなく、XMLだということを、、!
課題に取り組んでいるときはSwiftyJSONでJSON形式しか触ったことなかったのでどうしよう〜でした。
そんな過去の話は置いておき、以下の便利なライブラリを使用してみます。
SwiftyJSON風にかけるXML用のライブラリです。
こちらをAlamofireと組み合わせて使っていきます。
private func fetchRuby(text: String, completion: @escaping ((String) -> Void)) -> Thunk<AppState> {
return Thunk<AppState> { dispatch, getState in
let params = [
"appid": "XXXXXXXXXXXXXXXXXXX",
"sentence": text,
]
AF.request("https://jlp.yahooapis.jp/FuriganaService/V1/furigana",
method: .get,
parameters: params,
encoding: URLEncoding.default,
headers: nil
)
.response { (response) in
guard let data = response.data else {
print("cannot get XML")
return
}
let xml = SWXMLHash.parse(data)
var ruby = ""
let wordCount = xml["ResultSet"]["Result"]["WordList"]["Word"].all.count
if wordCount == 0 {
print("word count is 0")
}else{
for i in 0...wordCount - 1 {
if let furigana = xml["ResultSet"]["Result"]["WordList"]["Word"][i]["Furigana"].element?.text {
ruby += furigana
}else if let notFurigana = xml["ResultSet"]["Result"]["WordList"]["Word"][i]["Surface"].element?.text {
ruby += notFurigana
}
}
completion(ruby)
}
}
}
}
リクエストはこんな感じ。センスがなくてすみません。一年前に書いたやつをコピペして使ってます。
ちなみにXMLレスポンスはこのように返ってきます。
<ResultSet xsi:schemaLocation="urn:yahoo:jp:jlp:FuriganaService https://jlp.yahooapis.jp/FuriganaService/V1/furigana.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="urn:yahoo:jp:jlp:FuriganaService">
<Result>
<WordList>
<Word>
<Surface>白日</Surface>
<Furigana>はくじつ</Furigana>
<Roman>hakuzitu</Roman>
</Word>
</WordList>
</Result>
</ResultSet>
これを
let furigana = xml["ResultSet"]["Result"]["WordList"]["Word"][i]["Furigana"].element?.text
A-Z五十音順にソートする
上記のリクエストメソッドでは完了ハンドラをつけているので、レスポンスの振り仮名が返るようになっています。
それを利用して、次のソートメソッド x Entity追加メソッドに渡してあげる。
public func createNewSong(title: String, artist: String, key: Int, tags: [String], completion: @escaping (([Entity.Song]) -> Void)) -> Thunk<AppState> {
return Thunk<AppState> { dispatch, getState in
dispatch(fetchRuby(text: title, completion: { kana in
let entity = Entity.Song(id: 999, title: title, kana: kana, artist: artist,
rate: 0, key: key, tags: tags)
var songs = store.state.songsState.allSongsState.allSongs // stateで管理してる全曲分リストデータ
// appending antity
songs.append(entity)
// sort by alphabet
let alphabeticalList = songs.sorted(by: { $0.title < $1.title }) // ここでソート
// modify id
let changedIdList = alphabeticalList.enumerated().map { (index: Int, song: Entity.Song) -> Entity.Song in
var track = song
track.id = index
return track
}
dispatch(SongsState.updateSongs(changedIdList))
completion(changedIdList)
}))
}
}
Swiftにはデフォルトでソートメソッドが用意してあります。
構造体のプロパティを利用してソートしたい場合、sort() が利用できるので使ってみましょう。
今回は、
- アルファベットはA-Z
- 日本語は五十音順
でソートしたいので
let alphabeticalList = songs.sorted(by: { $0.title < $1.title })
としました。
これを $0.title > $1.title
とすると、結果が逆になります。
あとはEntityにルビをプロパティとして与えてあげて、それを元にTableViewに表示すればOKです。
まとめ
大まかな流れとしては
- Yahoo API で取得したひらがなを取得
- 完了ハンドラでソート&Entity作成メソッドにルビを渡してあげる
- ルビをプロパティに持ったEntityを作成し、全曲リストに追加
- 全曲リストをソート
- tableViewで表示
こんな感じです。
このリストにTableViewHeaderなどを作成すれば、いい感じの五十音順リストが作れるかと思いますよ!
もしよかったら楽チンなAPIなので使ってみてくれよな!
お疲れさん!
じゃーな!
ディスカッション
コメント一覧
まだ、コメントがありません