Skip to content

Commit

Permalink
Fixing the handling of Hsu and Eten26 arranges with all possible test…
Browse files Browse the repository at this point in the history
… cases. (#14)

* Add certain Composer functions.

* Fix handleHsu() and handleEten26().

* Add test cases for handling Hsu / Dachen26 / Eten26 arranges.
  • Loading branch information
ShikiSuen authored May 16, 2022
1 parent b321e90 commit c2a48db
Show file tree
Hide file tree
Showing 2 changed files with 3,140 additions and 81 deletions.
245 changes: 164 additions & 81 deletions Sources/Tekkon/TekkonSyllableComposer.swift
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,14 @@ public struct Tekkon {
valueStorage = ""
}

/// 自我變換資料值。
/// - Parameters:
/// - strOf: 要取代的內容。
/// - strWith: 要取代成的內容。
mutating func selfReplace(_ strOf: String, _ strWith: String = "") {
valueStorage = valueStorage.replacingOccurrences(of: strOf, with: strWith)
}

// MARK: - Misc Definitions

/// 這些內容用來滿足 "Equatable, Hashable, ExpressibleByStringLiteral" 需求。
Expand Down Expand Up @@ -231,12 +239,17 @@ public struct Tekkon {
intonation.isEmpty && vowel.isEmpty && semivowel.isEmpty && consonant.isEmpty
}

/// 注拼槽內容是否為空。
public var isPronouncable: Bool {
!vowel.isEmpty || !semivowel.isEmpty || !consonant.isEmpty
}

// MARK: 注拼槽對外處理函數

/// 初期化一個新的注拼槽。可以藉由 @input 參數指定初期已經傳入的按鍵訊號。
/// 還可以在初期化時藉由 @arrange 參數來指定注音排列(預設為「.ofDachen」大千佈局)。
/// - Parameters:
/// - input: 傳入的 String 內容。
/// - input: 傳入的 String 內容,用以處理單個字符
/// - arrange: 要使用的注音排列。
public init(_ input: String = "", arrange parser: MandarinParser = .ofDachen) {
ensureParser(arrange: parser)
Expand Down Expand Up @@ -318,6 +331,24 @@ public struct Tekkon {
}
}

/// 處理一連串的按鍵輸入。
/// - Parameters:
/// - givenSequence: 傳入的 String 內容,用以處理一整串擊鍵輸入。
public mutating func receiveSequence(_ givenSequence: String = "") {
clear()
for key in givenSequence {
receiveKey(fromString: String(key))
}
}

/// 處理一連串的按鍵輸入、且返回被處理之後的注音(陰平為空格)。
/// - Parameters:
/// - givenSequence: 傳入的 String 內容,用以處理一整串擊鍵輸入。
public mutating func convertSequenceToRawComposition(_ givenSequence: String = "") -> String {
receiveSequence(givenSequence)
return value
}

/// 專門用來響應使用者摁下 BackSpace 按鍵時的行為。
/// 刪除順序:調、韻、介、聲。
/// @--DISCUSSION--@
Expand Down Expand Up @@ -396,18 +427,27 @@ public struct Tekkon {
let incomingPhonabet = Phonabet(strReturn)

switch key {
case "d": if consonant.isEmpty { consonant = "" } else { intonation = "˙" }
case "f": if consonant.isEmpty { consonant = "" } else { intonation = "ˊ" }
case "h": if consonant.isEmpty { consonant = "" } else { vowel = "" }
case "j": if consonant.isEmpty { consonant = "" } else { intonation = "ˇ" }
case "k": if consonant.isEmpty { consonant = "" } else { intonation = "ˋ" }
case "l": if consonant.isEmpty { consonant = "" } else { vowel = "" }
case "m": if consonant.isEmpty { consonant = "" } else { vowel = "" }
case "n": if consonant.isEmpty { consonant = "" } else { vowel = "" }
case "p": if consonant.isEmpty { consonant = "" } else { vowel = "" }
case "q": if consonant.isEmpty { consonant = "" } else { vowel = "" }
case "t": if consonant.isEmpty { consonant = "" } else { vowel = "" }
case "w": if consonant.isEmpty { consonant = "" } else { vowel = "" }
case "d": if !isPronouncable { consonant = "" } else { intonation = "˙" }
case "f": if !isPronouncable { consonant = "" } else { intonation = "ˊ" }
case "j": if !isPronouncable { consonant = "" } else { intonation = "ˇ" }
case "k": if !isPronouncable { consonant = "" } else { intonation = "ˋ" }
case "h": if consonant.isEmpty, semivowel.isEmpty { consonant = "" } else { vowel = "" }
case "l": if consonant.isEmpty, semivowel.isEmpty { consonant = "" } else { vowel = "" }
case "m": if consonant.isEmpty, semivowel.isEmpty { consonant = "" } else { vowel = "" }
case "n": if consonant.isEmpty, semivowel.isEmpty { consonant = "" } else { vowel = "" }
case "q": if consonant.isEmpty, semivowel.isEmpty { consonant = "" } else { vowel = "" }
case "t": if consonant.isEmpty, semivowel.isEmpty { consonant = "" } else { vowel = "" }
case "w": if consonant.isEmpty, semivowel.isEmpty { consonant = "" } else { vowel = "" }
case "p":
if consonant.isEmpty, semivowel.isEmpty {
consonant = ""
} else if consonant.isEmpty, semivowel == "" {
vowel = ""
} else if consonant.isEmpty {
vowel = ""
} else {
vowel = ""
}
default: break
}

Expand Down Expand Up @@ -439,6 +479,20 @@ public struct Tekkon {
}
}

if "dfjk ".contains(key),
!consonant.isEmpty, semivowel.isEmpty, vowel.isEmpty
{
consonant.selfReplace("", "")
consonant.selfReplace("", "")
consonant.selfReplace("", "")
consonant.selfReplace("", "")
consonant.selfReplace("", "")
consonant.selfReplace("", "")
}

// 後置修正
if value == "ㄍ˙" { consonant = "" }

// 這些按鍵在上文處理過了,就不要再回傳了。
if "dfhjklmnpqtw".contains(key) { strReturn = "" }

Expand All @@ -456,63 +510,112 @@ public struct Tekkon {
strReturn = Tekkon.mapHsuStaticKeys[key] ?? ""
let incomingPhonabet = Phonabet(strReturn)

if key == " ", value == "" {
consonant = ""
vowel = ""
}

switch key {
case "a": if consonant.isEmpty { consonant = "" } else { vowel = "" }
case "d": if consonant.isEmpty { consonant = "" } else { intonation = "ˊ" }
case "d": if isPronouncable { intonation = "ˊ" } else { consonant = "" }
case "f": if isPronouncable { intonation = "ˇ" } else { consonant = "" }
case "s": if isPronouncable { intonation = "˙" } else { consonant = "" }
case "j": if isPronouncable { intonation = "ˋ" } else { consonant = "" }
case "a": if consonant.isEmpty, semivowel.isEmpty { consonant = "" } else { vowel = "" }
case "v": if semivowel.isEmpty { consonant = "" } else { consonant = "" }
case "c": if semivowel.isEmpty { consonant = "" } else { consonant = "" }
case "e": if semivowel.isEmpty { semivowel = "" } else { vowel = "" }
case "f": if consonant.isEmpty { consonant = "" } else { intonation = "ˇ" }
case "g": if consonant.isEmpty { consonant = "" } else { vowel = "" }
case "h": if consonant.isEmpty { consonant = "" } else { vowel = "" }
case "k": if consonant.isEmpty { consonant = "" } else { vowel = "" }
case "g": if consonant.isEmpty, semivowel.isEmpty { consonant = "" } else { vowel = "" }
case "h": if consonant.isEmpty, semivowel.isEmpty { consonant = "" } else { vowel = "" }
case "k": if consonant.isEmpty, semivowel.isEmpty { consonant = "" } else { vowel = "" }
case "m": if consonant.isEmpty, semivowel.isEmpty { consonant = "" } else { vowel = "" }
case "n": if consonant.isEmpty, semivowel.isEmpty { consonant = "" } else { vowel = "" }
case "l":
if value.isEmpty, !consonant.isEmpty, !semivowel.isEmpty {
vowel = ""
} else if consonant.isEmpty {
} else if consonant.isEmpty, semivowel.isEmpty {
consonant = ""
} else {
vowel = ""
}
case "m": if consonant.isEmpty { consonant = "" } else { vowel = "" }
case "n": if consonant.isEmpty { consonant = "" } else { vowel = "" }
case "s": if consonant.isEmpty { consonant = "" } else { intonation = "˙" }
default: break
}
// 處理「一個按鍵對應兩個聲母」的情形。
if !consonant.isEmpty, incomingPhonabet.type == .semivowel {
switch consonant {
case "": // 許氏鍵盤應該也需要這個自動糾正
switch incomingPhonabet {
case "": consonant = "" // ㄑㄧ
case "": consonant = "" // ㄍㄨ
case "": consonant = "" // ㄑㄩ
default: break
}
case "":
if intonation.isEmpty {

// 處理特殊情形。
switch incomingPhonabet.type {
case .semivowel:
switch consonant {
case "": // 許氏鍵盤應該也需要這個自動糾正
switch incomingPhonabet {
case "": consonant = "" // ㄐㄧ
case "": consonant = "" // ㄓㄨ
case "": consonant = "" // ㄐㄩ
case "": consonant = "" // ㄑㄧ
case "": consonant = "" // ㄍㄨ
case "": consonant = "" // ㄑㄩ
default: break
}
}
case "":
switch incomingPhonabet {
case "": consonant = "" // ㄒㄧ
case "": consonant = "" // ㄕㄨ
case "": consonant = "" // ㄒㄩ
default: break
}
default: break
}
case "":
if intonation.isEmpty {
switch incomingPhonabet {
case "": consonant = "" // ㄐㄧ
case "": consonant = "" // ㄓㄨ
case "": consonant = "" // ㄐㄩ
default: break
}
}
case "":
if intonation.isEmpty {
switch incomingPhonabet {
case "": consonant = "" // ㄐㄧ
case "": consonant = "" // ㄓㄨ
case "": consonant = "" // ㄐㄩ
default: break
}
}
case "":
switch incomingPhonabet {
case "": consonant = "" // ㄒㄧ
case "": consonant = "" // ㄕㄨ
case "": consonant = "" // ㄒㄩ
default: break
}
default: break
}
case .vowel:
if semivowel.isEmpty {
consonant.selfReplace("", "")
consonant.selfReplace("", "")
consonant.selfReplace("", "")
}
default: break
}

if key == "j" { // 對該按鍵作為調號的處理得放在最後
if !consonant.isEmpty { intonation = "ˋ" }
if "dfjs ".contains(key) {
if !consonant.isEmpty, semivowel.isEmpty, vowel.isEmpty {
consonant.selfReplace("", "")
consonant.selfReplace("", "")
consonant.selfReplace("", "")
consonant.selfReplace("", "")
consonant.selfReplace("", "")
}
if !consonant.isEmpty, vowel.isEmpty {
consonant.selfReplace("", "")
}
if "ㄢㄣㄤㄥ".contains(vowel.value), semivowel.isEmpty {
consonant.selfReplace("", "")
consonant.selfReplace("", "")
consonant.selfReplace("", "")
}
if "ㄐㄑㄒ".contains(consonant.value), semivowel.isEmpty {
consonant.selfReplace("", "")
consonant.selfReplace("", "")
consonant.selfReplace("", "")
}
if vowel == "", semivowel.isEmpty { consonant.selfReplace("", "") }
}

// 後置修正
if value == "ㄔ˙" { consonant = "" }

// 這些按鍵在上文處理過了,就不要再回傳了。
if "adefghklmns".contains(key) { strReturn = "" }
if "acdefghjklmns".contains(key) { strReturn = "" }

// 回傳結果是空的話,不要緊,因為上文已經代處理過分配過程了。
return strReturn
Expand All @@ -528,15 +631,19 @@ public struct Tekkon {
strReturn = Tekkon.mapDachenCP26StaticKeys[key] ?? ""

switch key {
case "q": if consonant.isEmpty || consonant == "" { consonant = "" } else { consonant = "" }
case "w": if consonant.isEmpty || consonant == "" { consonant = "" } else { consonant = "" }
case "t": if consonant.isEmpty || consonant == "" { consonant = "" } else { consonant = "" }
case "e": if isPronouncable { intonation = "ˊ" } else { consonant = "" }
case "r": if isPronouncable { intonation = "ˇ" } else { consonant = "" }
case "d": if isPronouncable { intonation = "ˋ" } else { consonant = "" }
case "y": if isPronouncable { intonation = "˙" } else { consonant = "" }
case "b": if !consonant.isEmpty || !semivowel.isEmpty { vowel = "" } else { consonant = "" }
case "i": if vowel.isEmpty || vowel == "" { vowel = "" } else { vowel = "" }
case "l": if vowel.isEmpty || vowel == "" { vowel = "" } else { vowel = "" }
case "n": if !consonant.isEmpty || !semivowel.isEmpty { vowel = "" } else { consonant = "" }
case "o": if vowel.isEmpty || vowel == "" { vowel = "" } else { vowel = "" }
case "p": if vowel.isEmpty || vowel == "" { vowel = "" } else { vowel = "" }
case "n": if !consonant.isEmpty || !semivowel.isEmpty { vowel = "" } else { consonant = "" }
case "b": if !consonant.isEmpty || !semivowel.isEmpty { vowel = "" } else { consonant = "" }
case "q": if consonant.isEmpty || consonant == "" { consonant = "" } else { consonant = "" }
case "t": if consonant.isEmpty || consonant == "" { consonant = "" } else { consonant = "" }
case "w": if consonant.isEmpty || consonant == "" { consonant = "" } else { consonant = "" }
case "m":
if semivowel == "", vowel != "" {
semivowel = ""
Expand All @@ -563,30 +670,6 @@ public struct Tekkon {
} else {
semivowel = ""
}
case "e":
if !consonant.isEmpty || !semivowel.isEmpty || !vowel.isEmpty || consonant == "" {
intonation = "ˊ"
} else {
consonant = ""
}
case "r":
if !consonant.isEmpty || !semivowel.isEmpty || !vowel.isEmpty || consonant == "" {
intonation = "ˇ"
} else {
consonant = ""
}
case "d":
if !consonant.isEmpty || !semivowel.isEmpty || !vowel.isEmpty || consonant == "" {
intonation = "ˋ"
} else {
consonant = ""
}
case "y":
if !consonant.isEmpty || !semivowel.isEmpty || !vowel.isEmpty || consonant == "" {
intonation = "˙"
} else {
consonant = ""
}
default: break
}

Expand Down Expand Up @@ -829,7 +912,7 @@ public struct Tekkon {
/// 在這裡將二十六個字母寫全,也只是為了方便做 validity check。
/// 這裡提前對複音按鍵做處理,然後再用程式判斷介母類型、據此判斷是否需要做複音切換。
static let mapHsuStaticKeys: [String: String] = [
"a": "", "b": "", "c": "", "d": "", "e": "", "f": "", "g": "", "h": "", "i": "", "j": "", "k": "",
"a": "", "b": "", "c": "", "d": "", "e": "", "f": "", "g": "", "h": "", "i": "", "j": "", "k": "",
"l": "", "m": "", "n": "", "o": "", "p": "", "r": "", "s": "", "t": "", "u": "", "v": "", "w": "",
"x": "", "y": "", "z": "", " ": " ",
]
Expand Down
Loading

0 comments on commit c2a48db

Please sign in to comment.