Upgrade to Pro — share decks privately, control downloads, hide ads and more …

日本語でもいい感じに改行したい!! / Split Japanese sentence for UILabel and SwiftUI Text

B4edef9fde5f33ef95409f564d21e542?s=47 Trickart
September 18, 2021

日本語でもいい感じに改行したい!! / Split Japanese sentence for UILabel and SwiftUI Text

iOSDC2021発表資料

B4edef9fde5f33ef95409f564d21e542?s=128

Trickart

September 18, 2021
Tweet

Transcript

  1. 日本語でもいい感じに改 行したい!! trickart(@trickart4121)

  2. みなさん

  3. こういった 経験ありませんか?

  4. レイアウトはこんな感じでいいか!

  5. 一応初代SEでも確認しておくか…

  6. よいしょ…ん…?

  7. あっ…!!

  8. None
  9. 変なところで改行されてし まっている!! 😇

  10. 幅に合わせて縮めるやつでいいじゃん - adjustFontSizeToFitWidthをtrueにする - これで解決!!

  11. None
  12. お品書き - 一行表示じゃダメなケースについて - UILabelの改行制御(NSLineBreakMode) - 制御文字について(WORD JOINER) - 形態素解析

    - 改行制御ツールの実装 - パッケージング - おまけ
  13. 一行表示では良くないときある… - フォントサイズを縮めたくないことも… - ユーザー層的にフォントは大きくしておきたい場合 - めちゃ長テキストで米粒サイズになってしまう場合 - etc…

  14. あらかじめ改行しておけば…? 「iOSDC/2021/開催中」とした

  15. あらかじめ改行しておけば…? 12 Pro Maxでは改行されすぎてる感じがしてしまう… そもそもあらかじめやっておけない場合もある

  16. どうすれば…😇

  17. UILabelって こういうとこいい感じに やってくれないの…?

  18. もちろんやってくれます!

  19. 英語なら!!

  20. NSLineBreakMode - Viewの幅より長かったときどうするか? - そのままクリップする(byClipping) - はみ出す文字の前で改行する(byCharWapping) - はみ出す単語の前で改行する(byWordWrapping) -

    etc…
  21. でも日本語だと .byWordWrappingでも…

  22. 😇

  23. つまり 「Word」扱いされてない ってコト…?

  24. そんなときは… WORD JOINER!!

  25. WORD JOINERとは? - 制御文字の一種 - 幅がゼロの文字で、挿入した箇所は改行されなくなる - Unicodeのコードポイントは2060 →これを単語内にたくさん挿入すればいいはず

  26. 実験 - WORD JOINERを入れる・入れないで比較

  27. 実験 - WORD JOINERを入れる・入れないで比較 🎉

  28. これで 改行させない方法は わかった。

  29. じゃあ逆に どこで改行させれば…?

  30. 手作業は…

  31. こんなときは… 形態素解析!!

  32. 形態素解析とは 文法的な情報の注記の無い自然言語のテキストデータ(文)から、対象言語の文法や、辞書と呼ばれる単語 の品詞等の情報にもとづき、形態素(Morpheme, おおまかにいえば、言語で意味を持つ最小単位)の列に分 割し、それぞれの形態素の品詞等を判別する作業である。 by 形態素解析 – Wikipedia →単語の分割と品詞判別ができる!!

  33. OSSな形態素解析エンジン - ChaSen - JUMAN - MeCab ←今回はこれを使います

  34. MeCabとは - 工藤拓氏によって開発された形態素解析エンジン - C++製でC言語、Java、Python、Rubyからも利用可能 - BSD/GPL/LGPLのトリプルライセンス - macOSやiOSでも利用されている -

    Homebrewで簡単にインストールできる
  35. MeCabとは

  36. MeCabをSwiftからどう使う? - MeCabはC++製 - 今の所Swiftから直接C++ライブラリを使うことはできない →Objective-C++を使えばOK!! MeCabのC APIとSwiftのC Interopを使う案についてはおまけに

  37. Objective-C++とは? - Objective-C++はObjective-CとC++を合体させた言語 - 拡張子は.mm - Objective-C++からC++のクラスを扱える - Swift →

    Objective-C++ → C++
  38. Objective-C++とは? Objective-C++ C言語 オブジェクト指向 Objective-C C++

  39. 全体像 MeCab (C++) ツール (Swift) ラッパー (Objective-C++)

  40. ラッパーを書く - Objective-C++でただひたすら書く - 構造体とかStringをSwift向けに変換したりする - MeCabはchar *を返すのでNSStringに変換

  41. - やっぱりSwift Packageとして使いたい - ラッパーだけでなくMeCab自身や辞書データもSwift Packageにする 書いたラッパーをSwift Packageにする

  42. - C++なのにSwift Package? - Swift PackageはC/C++/Objective-C/Objective-C++の コードをパッケージング出来る - 1ターゲットにSwiftとObjective-Cを同居させたりすること はできない

    MeCab as a Swift Package
  43. - ビルド設定はPackage.swiftで行う - defineはcSettingsのdefine MeCab as a Swift Package

  44. - コンパイラに渡す設定はPackage.swiftで行う - ライブラリのリンクはlinkerSettingsのlinkedLibrary - iOSにもiconvはあるので安心 MeCab as a Swift

    Package
  45. - Objective-C/SwiftからC/C++のライブラリを使うためには module.modulemapが必要 MeCab as a Swift Package

  46. - 辞書データをSwift Packageにするには? - Swift 5.3からSwift PackageにBundleを追加することが出来 るようになった →辞書データだけBundleしたパッケージを作る MeCabIPAdic

    as a Swift Package
  47. - Swift PackageにファイルをBundleするにはresourcesで copyすればOK MeCabIPAdic as a Swift Package

  48. これでSwiftから MeCabが使える!! \\٩( 'ω' ) و//

  49. 実装する - 単語に分割したら単語中の文字の間にWORD JOINERを 入れる 青いそら → 青い/そら → 青¥u{2060}い/そ¥u{2060}ら

  50. つなぐ単語 - すべての単語を分割してしまうと見栄えが良くない - すきとおっ/た (動詞/助動詞) - 夏/で/も (名詞/助詞/助詞) -

    句読点や括弧閉 (禁則処理) →これらは前の単語と結合してしまう
  51. 実装する

  52. あらかじめLocalizable.strings - あらかじめWORD JOINERを仕込んでおきたい - MeCabIPAdicがデカいので同梱したくない… - Localizable.stringsを出力するCLIコマンド - $

    muscat in.strings out.strings
  53. 完成!! - 名前はMuscatといいます - https://github.com/trickart/muscat

  54. 今度こそ

  55. 補足1 NLTaggerは? - AppleはNLTaggerというクラスを提供している - NLTaggerではだめなのか? - 英語だと単語分割・品詞判別できる - 日本語だと品詞が全部「OtherWord」になってしまう

    - 品詞がないと助詞の連結などができないためボツ MeCabを選んだのはぶっちゃけMeCabしか知らなかったから
  56. 補足2 SwiftUIは? - SwiftUIにはlineBreakModeとかないけど使えるの? - 特に何も指定してないけど使えます!!

  57. 補足3 辞書データについて - MuscatではMeCabIPAdicを使用 - 辞書は差し替えようと思えば差し替えられるため mecab-ipadic-NEologdを使ったりすることも可能

  58. 補足4 muscat CLIの実装について - 引数やオプションの処理はswift-argument-parserを使用 - Property Wrapperでスッキリしてるのでおすすめ - Localizable.stringsはPropertyListDecoderで読み込める

    - ただ普通に[String:String]でデコードするとDictionaryは 順番を保証しないので順番が不定になってしまう - swift-collectionsのOrderedDictionaryを使えば…?
  59. 補足5 先行事例について - 作ったあとに先行事例について調べたらあった - GoogleのBudou 🍇 - Python製のツールで形態素解析して単語の区切に HTMLのspanタグを挿入するツール

    - よく考えたら昔Googleのブログで見たかも… - Muscatの名前はBudouにあやかってつけました
  60. 補足6 MeCab C APIとSwift C Interop - MeCabはC++製だがC言語向けのAPIがある - SwiftはC言語の関数を使用できる

    - Objective-C++使わなくてもいいのでは…? - 試したところXcodeでデバッグ実行したらメモリリーク警告 が発生 - 実装が悪いかもしれないが、原因が特定できなかった 為断念した - 将来追加されるであろうSwift C++ Interopに期待
  61. ご清聴ありがとうございました 参考資料 MeCab: Yet Another Part-of-Speech and Morphological Analyzer Bundling

    Resources with a Swift Package | Apple Developer Documentation C++ライブラリをiOSプロジェクトに追加する方法について - Zenn