// // extension Character.swift // Keyboard // // Created by ensan on 2020/09/03. // Copyright © 2020 ensan. All rights reserved. // import Foundation public enum CharacterUtils { /// 小書きのかなカナ集合 private static let kogakiKana: Set = [ "ぁ", "ぃ", "ぅ", "ぇ", "ぉ", "ゕ", "ゖ", "っ", "ゃ", "ゅ", "ょ", "ゎ", "ァ", "ィ", "ゥ", "ェ", "ォ", "ヵ", "ヶ", "ッ", "ャ", "ュ", "ョ", "ヮ" ] /// 濁点付きのかなカナ集合 private static let dakutenKana: Set = [ "ゔ", "が", "ぎ", "ぐ", "げ", "ご", "ざ", "じ", "ず", "ぜ", "ぞ", "だ", "ぢ", "づ", "で", "ど", "ば", "び", "ぶ", "べ", "ぼ", "ヴ", "ガ", "ギ", "グ", "ゲ", "ゴ", "ザ", "ジ", "ズ", "ゼ", "ゾ", "ダ", "ヂ", "ヅ", "デ", "ド", "バ", "ビ", "ブ", "ベ", "ボ" ] /// 小書きかなか否か static func isKogana(_ character: Character) -> Bool { kogakiKana.contains(character) } /// 自分が小書きであれば該当する文字を返す。 public static func kogaki(_ character: Character) -> Character { switch character { case "あ": return "ぁ" case "い": return "ぃ" case "う": return "ぅ" case "え": return "ぇ" case "お": return "ぉ" case "か": return "ゕ" case "け": return "ゖ" case "つ": return "っ" case "や": return "ゃ" case "ゆ": return "ゅ" case "よ": return "ょ" case "わ": return "ゎ" case "ア": return "ァ" case "イ": return "ィ" case "ウ": return "ゥ" case "エ": return "ェ" case "オ": return "ォ" case "カ": return "ヵ" case "ケ": return "ヶ" case "ツ": return "ッ" case "ヤ": return "ャ" case "ユ": return "ュ" case "ヨ": return "ョ" case "ワ": return "ヮ" default: return character } } /// 小書きから大書きを返す public static func ogaki(_ character: Character) -> Character { switch character { case "ぁ": return "あ" case "ぃ": return "い" case "ぅ": return "う" case "ぇ": return "え" case "ぉ": return "お" case "ゕ": return "か" case "ゖ": return "け" case "っ": return "つ" case "ゃ": return "や" case "ゅ": return "ゆ" case "ょ": return "よ" case "ゎ": return "わ" case "ァ": return "ア" case "ィ": return "イ" case "ゥ": return "ウ" case "ェ": return "エ" case "ォ": return "オ" case "ヵ": return "カ" case "ヶ": return "ケ" case "ッ": return "ツ" case "ャ": return "ヤ" case "ュ": return "ユ" case "ョ": return "ヨ" case "ヮ": return "ワ" default: return character } } /// 濁点付きか否か public static func isDakuten(_ character: Character) -> Bool { dakutenKana.contains(character) } /// 濁点をつけて返す public static func dakuten(_ character: Character) -> Character { switch character { case"う": return "ゔ" case"か": return "が" case"き": return "ぎ" case"く": return "ぐ" case"け": return "げ" case"こ": return "ご" case"さ": return "ざ" case"し": return "じ" case"す": return "ず" case"せ": return "ぜ" case"そ": return "ぞ" case"た": return "だ" case"ち": return "ぢ" case"つ": return "づ" case"て": return "で" case"と": return "ど" case"は": return "ば" case"ひ": return "び" case"ふ": return "ぶ" case"へ": return "べ" case"ほ": return "ぼ" case"ウ": return "ヴ" case"カ": return "ガ" case"キ": return "ギ" case"ク": return "グ" case"ケ": return "ゲ" case"コ": return "ゴ" case"サ": return "ザ" case"シ": return "ジ" case"ス": return "ズ" case"セ": return "ゼ" case"ソ": return "ゾ" case"タ": return "ダ" case"チ": return "ヂ" case"ツ": return "ヅ" case"テ": return "デ" case"ト": return "ド" case"ハ": return "バ" case"ヒ": return "ビ" case"フ": return "ブ" case"ヘ": return "ベ" case"ホ": return "ボ" default: return character } } /// 濁点を外して返す public static func mudakuten(_ character: Character) -> Character { switch character { case"ゔ": return "う" case"が": return "か" case"ぎ": return "き" case"ぐ": return "く" case"げ": return "け" case"ご": return "こ" case"ざ": return "さ" case"じ": return "し" case"ず": return "す" case"ぜ": return "せ" case"ぞ": return "そ" case"だ": return "た" case"ぢ": return "ち" case"づ": return "つ" case"で": return "て" case"ど": return "と" case"ば": return "は" case"び": return "ひ" case"ぶ": return "ふ" case"べ": return "へ" case"ぼ": return "ほ" case"ヴ": return "ウ" case"ガ": return "カ" case"ギ": return "キ" case"グ": return "ク" case"ゲ": return "ケ" case"ゴ": return "コ" case"ザ": return "サ" case"ジ": return "シ" case"ズ": return "ス" case"ゼ": return "セ" case"ゾ": return "ソ" case"ダ": return "タ" case"ヂ": return "チ" case"ヅ": return "ツ" case"デ": return "テ" case"ド": return "ト" case"バ": return "ハ" case"ビ": return "ヒ" case"ブ": return "フ" case"ベ": return "ヘ" case"ボ": return "ホ" default: return character } } /// 半濁点かどうか public static func isHandakuten(_ character: Character) -> Bool { [ "ぱ", "ぴ", "ぷ", "ぺ", "ぽ", "パ", "ピ", "プ", "ペ", "ポ" ].contains(character) } /// 半濁点をつけて返す public static func handakuten(_ character: Character) -> Character { switch character { case"は": return "ぱ" case"ひ": return "ぴ" case"ふ": return "ぷ" case"へ": return "ぺ" case"ほ": return "ぽ" case"ハ": return "パ" case"ヒ": return "ピ" case"フ": return "プ" case"ヘ": return "ペ" case"ホ": return "ポ" default: return character } } /// 半濁点を外して返す public static func muhandakuten(_ character: Character) -> Character { switch character { case"ぱ": return "は" case"ぴ": return "ひ" case"ぷ": return "ふ" case"ぺ": return "へ" case"ぽ": return "ほ" case"パ": return "ハ" case"ピ": return "ヒ" case"プ": return "フ" case"ペ": return "ヘ" case"ポ": return "ホ" default: return character } } /// 濁点、小書き、半濁点などを相互に変換する関数。 public static func requestChange(_ character: Character) -> String { if character.isLowercase { return character.uppercased() } if character.isUppercase { return character.lowercased() } if Set(["あ", "い", "え", "お", "や", "ゆ", "よ", "わ"]).contains(character) { return String(kogaki(character)) } if Set(["ぁ", "ぃ", "ぇ", "ぉ", "ゃ", "ゅ", "ょ", "ゎ"]).contains(character) { return String(ogaki(character)) } if Set(["か", "き", "く", "け", "こ", "さ", "し", "す", "せ", "そ", "た", "ち", "て", "と"]).contains(character) { return String(dakuten(character)) } if Set(["が", "ぎ", "ぐ", "げ", "ご", "ざ", "じ", "ず", "ぜ", "ぞ", "だ", "ぢ", "で", "ど"]).contains(character) { return String(mudakuten(character)) } if Set(["つ", "う"]).contains(character) { return String(kogaki(character)) } if Set(["っ", "ぅ"]).contains(character) { return String(dakuten(ogaki(character))) } if Set(["づ", "ゔ"]).contains(character) { return String(mudakuten(character)) } if Set(["は", "ひ", "ふ", "へ", "ほ"]).contains(character) { return String(dakuten(character)) } if Set(["ば", "び", "ぶ", "べ", "ぼ"]).contains(character) { return String(handakuten(mudakuten(character))) } if Set(["ぱ", "ぴ", "ぷ", "ぺ", "ぽ"]).contains(character) { return String(muhandakuten(character)) } return String(character) } } public extension Character { /// Returns the Katakanized version of the character. @inlinable func toKatakana() -> Character { if self.unicodeScalars.count != 1 { return self } let scalar = self.unicodeScalars.first! if 0x3041 <= scalar.value && scalar.value <= 0x3096 { return Character(UnicodeScalar(scalar.value + 96)!) } else { return self } } /// Returns the Hiraganized version of the character. @inlinable func toHiragana() -> Character { if self.unicodeScalars.count != 1 { return self } let scalar = self.unicodeScalars.first! if 0x30A1 <= scalar.value && scalar.value <= 0x30F6 { return Character(UnicodeScalar(scalar.value - 96)!) } else { return self } } }