Megrez // Use [String] as key in lieu of String.
This commit is contained in:
parent
ebaf44c7dc
commit
9b78be6d3a
|
@ -21,7 +21,7 @@ extension Megrez {
|
||||||
/// 該軌格內可以允許的最大幅位長度。
|
/// 該軌格內可以允許的最大幅位長度。
|
||||||
public static var maxSpanLength: Int = 10 { didSet { maxSpanLength = max(6, maxSpanLength) } }
|
public static var maxSpanLength: Int = 10 { didSet { maxSpanLength = max(6, maxSpanLength) } }
|
||||||
/// 公開:多字讀音鍵當中用以分割漢字讀音的記號的預設值,是「-」。
|
/// 公開:多字讀音鍵當中用以分割漢字讀音的記號的預設值,是「-」。
|
||||||
public static let kDefaultSeparator: String = "-"
|
public static var theSeparator: String = "-"
|
||||||
/// 該組字器的游標位置。
|
/// 該組字器的游標位置。
|
||||||
public var cursor: Int = 0 {
|
public var cursor: Int = 0 {
|
||||||
didSet {
|
didSet {
|
||||||
|
@ -33,7 +33,12 @@ extension Megrez {
|
||||||
/// 該組字器的標記器位置。
|
/// 該組字器的標記器位置。
|
||||||
public var marker: Int = 0 { didSet { marker = max(0, min(marker, length)) } }
|
public var marker: Int = 0 { didSet { marker = max(0, min(marker, length)) } }
|
||||||
/// 公開:多字讀音鍵當中用以分割漢字讀音的記號,預設為「-」。
|
/// 公開:多字讀音鍵當中用以分割漢字讀音的記號,預設為「-」。
|
||||||
public var separator = kDefaultSeparator
|
public var separator = theSeparator {
|
||||||
|
didSet {
|
||||||
|
Self.theSeparator = separator
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// 公開:組字器內已經插入的單筆索引鍵的數量。
|
/// 公開:組字器內已經插入的單筆索引鍵的數量。
|
||||||
public var width: Int { keys.count }
|
public var width: Int { keys.count }
|
||||||
/// 公開:最近一次爬軌結果。
|
/// 公開:最近一次爬軌結果。
|
||||||
|
@ -71,7 +76,7 @@ extension Megrez {
|
||||||
/// - Parameter key: 要插入的索引鍵。
|
/// - Parameter key: 要插入的索引鍵。
|
||||||
/// - Returns: 該操作是否成功執行。
|
/// - Returns: 該操作是否成功執行。
|
||||||
@discardableResult public mutating func insertKey(_ key: String) -> Bool {
|
@discardableResult public mutating func insertKey(_ key: String) -> Bool {
|
||||||
guard !key.isEmpty, key != separator, langModel.hasUnigramsFor(key: key) else { return false }
|
guard !key.isEmpty, key != separator, langModel.hasUnigramsFor(keyArray: [key]) else { return false }
|
||||||
keys.insert(key, at: cursor)
|
keys.insert(key, at: cursor)
|
||||||
let gridBackup = spans
|
let gridBackup = spans
|
||||||
resizeGrid(at: cursor, do: .expand)
|
resizeGrid(at: cursor, do: .expand)
|
||||||
|
@ -242,7 +247,7 @@ extension Megrez.Compositor {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
func getJointKeyArray(range: Range<Int>) -> [String] {
|
func getJoinedKeyArray(range: Range<Int>) -> [String] {
|
||||||
// 下面這句不能用 contains,不然會要求至少 macOS 13 Ventura。
|
// 下面這句不能用 contains,不然會要求至少 macOS 13 Ventura。
|
||||||
guard range.upperBound <= keys.count, range.lowerBound >= 0 else { return [] }
|
guard range.upperBound <= keys.count, range.lowerBound >= 0 else { return [] }
|
||||||
return keys[range].map { String($0) }
|
return keys[range].map { String($0) }
|
||||||
|
@ -262,11 +267,10 @@ extension Megrez.Compositor {
|
||||||
var nodesChanged = 0
|
var nodesChanged = 0
|
||||||
for position in range {
|
for position in range {
|
||||||
for theLength in 1...min(maxSpanLength, range.upperBound - position) {
|
for theLength in 1...min(maxSpanLength, range.upperBound - position) {
|
||||||
let jointKeyArray = getJointKeyArray(range: position..<(position + theLength))
|
let joinedKeyArray = getJoinedKeyArray(range: position..<(position + theLength))
|
||||||
let jointKey = jointKeyArray.joined(separator: separator)
|
if let theNode = getNode(at: position, length: theLength, keyArray: joinedKeyArray) {
|
||||||
if let theNode = getNode(at: position, length: theLength, keyArray: jointKeyArray) {
|
|
||||||
if !updateExisting { continue }
|
if !updateExisting { continue }
|
||||||
let unigrams = langModel.unigramsFor(key: jointKey)
|
let unigrams = langModel.unigramsFor(keyArray: joinedKeyArray)
|
||||||
// 自動銷毀無效的節點。
|
// 自動銷毀無效的節點。
|
||||||
if unigrams.isEmpty {
|
if unigrams.isEmpty {
|
||||||
if theNode.keyArray.count == 1 { continue }
|
if theNode.keyArray.count == 1 { continue }
|
||||||
|
@ -277,10 +281,10 @@ extension Megrez.Compositor {
|
||||||
nodesChanged += 1
|
nodesChanged += 1
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
let unigrams = langModel.unigramsFor(key: jointKey)
|
let unigrams = langModel.unigramsFor(keyArray: joinedKeyArray)
|
||||||
guard !unigrams.isEmpty else { continue }
|
guard !unigrams.isEmpty else { continue }
|
||||||
insertNode(
|
insertNode(
|
||||||
.init(keyArray: jointKeyArray, spanLength: theLength, unigrams: unigrams, keySeparator: separator),
|
.init(keyArray: joinedKeyArray, spanLength: theLength, unigrams: unigrams),
|
||||||
at: position
|
at: position
|
||||||
)
|
)
|
||||||
nodesChanged += 1
|
nodesChanged += 1
|
||||||
|
|
|
@ -32,7 +32,7 @@ extension Megrez.Compositor {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let terminal = Vertex(node: .init(keyArray: ["_TERMINAL_"], keySeparator: separator))
|
let terminal = Vertex(node: .init(keyArray: ["_TERMINAL_"]))
|
||||||
|
|
||||||
for (i, vertexSpan) in vertexSpans.enumerated() {
|
for (i, vertexSpan) in vertexSpans.enumerated() {
|
||||||
for vertex in vertexSpan {
|
for vertex in vertexSpan {
|
||||||
|
@ -47,7 +47,7 @@ extension Megrez.Compositor {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let root = Vertex(node: .init(keyArray: ["_ROOT_"], keySeparator: separator))
|
let root = Vertex(node: .init(keyArray: ["_ROOT_"]))
|
||||||
root.distance = 0
|
root.distance = 0
|
||||||
root.edges.append(contentsOf: vertexSpans[0])
|
root.edges.append(contentsOf: vertexSpans[0])
|
||||||
|
|
||||||
|
|
|
@ -7,49 +7,66 @@ import Foundation
|
||||||
|
|
||||||
extension Megrez.Compositor {
|
extension Megrez.Compositor {
|
||||||
public struct KeyValuePaired: Equatable, Hashable, Comparable, CustomStringConvertible {
|
public struct KeyValuePaired: Equatable, Hashable, Comparable, CustomStringConvertible {
|
||||||
/// 鍵。一般情況下用來放置讀音等可以用來作為索引的內容。
|
/// 鍵陣列。一般情況下用來放置讀音等可以用來作為索引的內容。
|
||||||
public var key: String
|
public var keyArray: [String]
|
||||||
/// 資料值。
|
/// 資料值。
|
||||||
public var value: String
|
public var value: String
|
||||||
/// 將當前鍵值列印成一個字串。
|
/// 將當前鍵值列印成一個字串。
|
||||||
public var description: String { "(" + key + "," + value + ")" }
|
public var description: String { "(" + keyArray.description + "," + value + ")" }
|
||||||
/// 判斷當前鍵值配對是否合規。如果鍵與值有任一為空,則結果為 false。
|
/// 判斷當前鍵值配對是否合規。如果鍵與值有任一為空,則結果為 false。
|
||||||
public var isValid: Bool { !key.isEmpty && !value.isEmpty }
|
public var isValid: Bool { !keyArray.joined().isEmpty && !value.isEmpty }
|
||||||
/// 將當前鍵值列印成一個字串,但如果該鍵值配對為空的話則僅列印「()」。
|
/// 將當前鍵值列印成一個字串,但如果該鍵值配對為空的話則僅列印「()」。
|
||||||
public var toNGramKey: String { !isValid ? "()" : "(" + key + "," + value + ")" }
|
public var toNGramKey: String { !isValid ? "()" : "(" + joinedKey() + "," + value + ")" }
|
||||||
|
|
||||||
|
/// 初期化一組鍵值配對。
|
||||||
|
/// - Parameters:
|
||||||
|
/// - key: 鍵陣列。一般情況下用來放置讀音等可以用來作為索引的內容。
|
||||||
|
/// - value: 資料值。
|
||||||
|
public init(keyArray: [String], value: String = "N/A") {
|
||||||
|
self.keyArray = keyArray.isEmpty ? ["N/A"] : keyArray
|
||||||
|
self.value = value.isEmpty ? "N/A" : value
|
||||||
|
}
|
||||||
|
|
||||||
/// 初期化一組鍵值配對。
|
/// 初期化一組鍵值配對。
|
||||||
/// - Parameters:
|
/// - Parameters:
|
||||||
/// - key: 鍵。一般情況下用來放置讀音等可以用來作為索引的內容。
|
/// - key: 鍵。一般情況下用來放置讀音等可以用來作為索引的內容。
|
||||||
/// - value: 資料值。
|
/// - value: 資料值。
|
||||||
public init(key: String = "", value: String = "") {
|
public init(key: String = "N/A", value: String = "N/A") {
|
||||||
self.key = key
|
keyArray = key.isEmpty ? ["N/A"] : key.components(separatedBy: Megrez.Compositor.theSeparator)
|
||||||
self.value = value
|
self.value = value.isEmpty ? "N/A" : value
|
||||||
}
|
}
|
||||||
|
|
||||||
public func hash(into hasher: inout Hasher) {
|
public func hash(into hasher: inout Hasher) {
|
||||||
hasher.combine(key)
|
hasher.combine(keyArray)
|
||||||
hasher.combine(value)
|
hasher.combine(value)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public func joinedKey(by separator: String = Megrez.Compositor.theSeparator) -> String {
|
||||||
|
keyArray.joined(separator: separator)
|
||||||
|
}
|
||||||
|
|
||||||
public static func == (lhs: KeyValuePaired, rhs: KeyValuePaired) -> Bool {
|
public static func == (lhs: KeyValuePaired, rhs: KeyValuePaired) -> Bool {
|
||||||
lhs.key == rhs.key && lhs.value == rhs.value
|
lhs.keyArray == rhs.keyArray && lhs.value == rhs.value
|
||||||
}
|
}
|
||||||
|
|
||||||
public static func < (lhs: KeyValuePaired, rhs: KeyValuePaired) -> Bool {
|
public static func < (lhs: KeyValuePaired, rhs: KeyValuePaired) -> Bool {
|
||||||
(lhs.key.count < rhs.key.count) || (lhs.key.count == rhs.key.count && lhs.value < rhs.value)
|
(lhs.keyArray.joined().count < rhs.keyArray.joined().count)
|
||||||
|
|| (lhs.keyArray.joined().count == rhs.keyArray.joined().count && lhs.value < rhs.value)
|
||||||
}
|
}
|
||||||
|
|
||||||
public static func > (lhs: KeyValuePaired, rhs: KeyValuePaired) -> Bool {
|
public static func > (lhs: KeyValuePaired, rhs: KeyValuePaired) -> Bool {
|
||||||
(lhs.key.count > rhs.key.count) || (lhs.key.count == rhs.key.count && lhs.value > rhs.value)
|
(lhs.keyArray.joined().count > rhs.keyArray.joined().count)
|
||||||
|
|| (lhs.keyArray.joined().count == rhs.keyArray.joined().count && lhs.value > rhs.value)
|
||||||
}
|
}
|
||||||
|
|
||||||
public static func <= (lhs: KeyValuePaired, rhs: KeyValuePaired) -> Bool {
|
public static func <= (lhs: KeyValuePaired, rhs: KeyValuePaired) -> Bool {
|
||||||
(lhs.key.count <= rhs.key.count) || (lhs.key.count == rhs.key.count && lhs.value <= rhs.value)
|
(lhs.keyArray.joined().count <= rhs.keyArray.joined().count)
|
||||||
|
|| (lhs.keyArray.joined().count == rhs.keyArray.joined().count && lhs.value <= rhs.value)
|
||||||
}
|
}
|
||||||
|
|
||||||
public static func >= (lhs: KeyValuePaired, rhs: KeyValuePaired) -> Bool {
|
public static func >= (lhs: KeyValuePaired, rhs: KeyValuePaired) -> Bool {
|
||||||
(lhs.key.count >= rhs.key.count) || (lhs.key.count == rhs.key.count && lhs.value >= rhs.value)
|
(lhs.keyArray.joined().count >= rhs.keyArray.joined().count)
|
||||||
|
|| (lhs.keyArray.joined().count == rhs.keyArray.joined().count && lhs.value >= rhs.value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -70,7 +87,7 @@ extension Megrez.Compositor {
|
||||||
}
|
}
|
||||||
let keyAtCursor = keys[location]
|
let keyAtCursor = keys[location]
|
||||||
for theNode in anchors.map(\.node) {
|
for theNode in anchors.map(\.node) {
|
||||||
if theNode.key.isEmpty { continue }
|
if theNode.keyArray.joined(separator: separator).isEmpty { continue }
|
||||||
for gram in theNode.unigrams {
|
for gram in theNode.unigrams {
|
||||||
switch filter {
|
switch filter {
|
||||||
case .all:
|
case .all:
|
||||||
|
@ -81,7 +98,7 @@ extension Megrez.Compositor {
|
||||||
case .endAt:
|
case .endAt:
|
||||||
if theNode.keyArray.reversed()[0] != keyAtCursor { continue }
|
if theNode.keyArray.reversed()[0] != keyAtCursor { continue }
|
||||||
}
|
}
|
||||||
result.append(.init(key: theNode.key, value: gram.value))
|
result.append(.init(keyArray: theNode.keyArray, value: gram.value))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return result
|
return result
|
||||||
|
@ -100,7 +117,7 @@ extension Megrez.Compositor {
|
||||||
)
|
)
|
||||||
-> Bool
|
-> Bool
|
||||||
{
|
{
|
||||||
overrideCandidateAgainst(key: candidate.key, at: location, value: candidate.value, type: overrideType)
|
overrideCandidateAgainst(keyArray: candidate.keyArray, at: location, value: candidate.value, type: overrideType)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 使用給定的候選字詞字串,將給定位置的節點的候選字詞改為與之一致的候選字詞。
|
/// 使用給定的候選字詞字串,將給定位置的節點的候選字詞改為與之一致的候選字詞。
|
||||||
|
@ -115,7 +132,7 @@ extension Megrez.Compositor {
|
||||||
_ candidate: String,
|
_ candidate: String,
|
||||||
at location: Int, overrideType: Node.OverrideType = .withHighScore
|
at location: Int, overrideType: Node.OverrideType = .withHighScore
|
||||||
) -> Bool {
|
) -> Bool {
|
||||||
overrideCandidateAgainst(key: nil, at: location, value: candidate, type: overrideType)
|
overrideCandidateAgainst(keyArray: nil, at: location, value: candidate, type: overrideType)
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: Internal implementations.
|
// MARK: Internal implementations.
|
||||||
|
@ -127,14 +144,18 @@ extension Megrez.Compositor {
|
||||||
/// - value: 資料值。
|
/// - value: 資料值。
|
||||||
/// - type: 指定覆寫行為。
|
/// - type: 指定覆寫行為。
|
||||||
/// - Returns: 該操作是否成功執行。
|
/// - Returns: 該操作是否成功執行。
|
||||||
internal func overrideCandidateAgainst(key: String?, at location: Int, value: String, type: Node.OverrideType)
|
internal func overrideCandidateAgainst(keyArray: [String]?, at location: Int, value: String, type: Node.OverrideType)
|
||||||
-> Bool
|
-> Bool
|
||||||
{
|
{
|
||||||
let location = max(min(location, keys.count), 0) // 防呆
|
let location = max(min(location, keys.count), 0) // 防呆
|
||||||
var arrOverlappedNodes: [NodeAnchor] = fetchOverlappingNodes(at: min(keys.count - 1, location))
|
var arrOverlappedNodes: [NodeAnchor] = fetchOverlappingNodes(at: min(keys.count - 1, location))
|
||||||
var overridden: NodeAnchor?
|
var overridden: NodeAnchor?
|
||||||
for anchor in arrOverlappedNodes {
|
for anchor in arrOverlappedNodes {
|
||||||
if let key = key, anchor.node.key != key { continue }
|
if let keyArray = keyArray,
|
||||||
|
anchor.node.keyArray.joined(separator: separator) != keyArray.joined(separator: separator)
|
||||||
|
{
|
||||||
|
continue
|
||||||
|
}
|
||||||
if anchor.node.selectOverrideUnigram(value: value, type: type) {
|
if anchor.node.selectOverrideUnigram(value: value, type: type) {
|
||||||
overridden = anchor
|
overridden = anchor
|
||||||
break
|
break
|
||||||
|
@ -150,7 +171,9 @@ extension Megrez.Compositor {
|
||||||
arrOverlappedNodes = fetchOverlappingNodes(at: i)
|
arrOverlappedNodes = fetchOverlappingNodes(at: i)
|
||||||
for anchor in arrOverlappedNodes {
|
for anchor in arrOverlappedNodes {
|
||||||
if anchor.node == overridden.node { continue }
|
if anchor.node == overridden.node { continue }
|
||||||
if !overridden.node.key.contains(anchor.node.key) || !overridden.node.value.contains(anchor.node.value) {
|
if !overridden.node.keyArray.joined(separator: separator).contains(
|
||||||
|
anchor.node.keyArray.joined(separator: separator)) || !overridden.node.value.contains(anchor.node.value)
|
||||||
|
{
|
||||||
anchor.node.reset()
|
anchor.node.reset()
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
|
@ -34,7 +34,8 @@ extension Megrez.Compositor {
|
||||||
/// 數(比如野獸常數),以讓「c」更容易單獨被選中。
|
/// 數(比如野獸常數),以讓「c」更容易單獨被選中。
|
||||||
public var overridingScore: Double = 114_514
|
public var overridingScore: Double = 114_514
|
||||||
|
|
||||||
public private(set) var key: String
|
// public var key: String { keyArray.joined(separator: Megrez.Compositor.theSeparator) }
|
||||||
|
|
||||||
public private(set) var keyArray: [String]
|
public private(set) var keyArray: [String]
|
||||||
public private(set) var spanLength: Int
|
public private(set) var spanLength: Int
|
||||||
public private(set) var unigrams: [Megrez.Unigram]
|
public private(set) var unigrams: [Megrez.Unigram]
|
||||||
|
@ -42,10 +43,10 @@ extension Megrez.Compositor {
|
||||||
didSet { currentUnigramIndex = max(min(unigrams.count - 1, currentUnigramIndex), 0) }
|
didSet { currentUnigramIndex = max(min(unigrams.count - 1, currentUnigramIndex), 0) }
|
||||||
}
|
}
|
||||||
|
|
||||||
public var currentPair: Megrez.Compositor.KeyValuePaired { .init(key: key, value: value) }
|
public var currentPair: Megrez.Compositor.KeyValuePaired { .init(keyArray: keyArray, value: value) }
|
||||||
|
|
||||||
public func hash(into hasher: inout Hasher) {
|
public func hash(into hasher: inout Hasher) {
|
||||||
hasher.combine(key)
|
hasher.combine(keyArray)
|
||||||
hasher.combine(spanLength)
|
hasher.combine(spanLength)
|
||||||
hasher.combine(unigrams)
|
hasher.combine(unigrams)
|
||||||
hasher.combine(currentUnigramIndex)
|
hasher.combine(currentUnigramIndex)
|
||||||
|
@ -68,14 +69,11 @@ extension Megrez.Compositor {
|
||||||
public private(set) var overrideType: Node.OverrideType
|
public private(set) var overrideType: Node.OverrideType
|
||||||
|
|
||||||
public static func == (lhs: Node, rhs: Node) -> Bool {
|
public static func == (lhs: Node, rhs: Node) -> Bool {
|
||||||
lhs.key == rhs.key && lhs.spanLength == rhs.spanLength
|
lhs.keyArray == rhs.keyArray && lhs.spanLength == rhs.spanLength
|
||||||
&& lhs.unigrams == rhs.unigrams && lhs.overrideType == rhs.overrideType
|
&& lhs.unigrams == rhs.unigrams && lhs.overrideType == rhs.overrideType
|
||||||
}
|
}
|
||||||
|
|
||||||
public init(
|
public init(keyArray: [String] = [], spanLength: Int = 0, unigrams: [Megrez.Unigram] = []) {
|
||||||
keyArray: [String] = [], spanLength: Int = 0, unigrams: [Megrez.Unigram] = [], keySeparator: String = ""
|
|
||||||
) {
|
|
||||||
key = keyArray.joined(separator: keySeparator)
|
|
||||||
self.keyArray = keyArray
|
self.keyArray = keyArray
|
||||||
self.spanLength = spanLength
|
self.spanLength = spanLength
|
||||||
self.unigrams = unigrams
|
self.unigrams = unigrams
|
||||||
|
@ -112,6 +110,10 @@ extension Megrez.Compositor {
|
||||||
overrideType = .withNoOverrides
|
overrideType = .withNoOverrides
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public func joinedKey(by separator: String = Megrez.Compositor.theSeparator) -> String {
|
||||||
|
keyArray.joined(separator: separator)
|
||||||
|
}
|
||||||
|
|
||||||
public func selectOverrideUnigram(value: String, type: Node.OverrideType) -> Bool {
|
public func selectOverrideUnigram(value: String, type: Node.OverrideType) -> Bool {
|
||||||
guard type != .withNoOverrides else {
|
guard type != .withNoOverrides else {
|
||||||
return false
|
return false
|
||||||
|
@ -136,7 +138,7 @@ extension Megrez.Compositor {
|
||||||
let spanIndex: Int // 幅位座標
|
let spanIndex: Int // 幅位座標
|
||||||
var spanLength: Int { node.spanLength }
|
var spanLength: Int { node.spanLength }
|
||||||
var unigrams: [Megrez.Unigram] { node.unigrams }
|
var unigrams: [Megrez.Unigram] { node.unigrams }
|
||||||
var key: String { node.key }
|
var keyArray: [String] { node.keyArray }
|
||||||
var value: String { node.value }
|
var value: String { node.value }
|
||||||
|
|
||||||
/// 將該節錨雜湊化。
|
/// 將該節錨雜湊化。
|
||||||
|
@ -154,7 +156,12 @@ extension Array where Element == Megrez.Compositor.Node {
|
||||||
public var values: [String] { map(\.value) }
|
public var values: [String] { map(\.value) }
|
||||||
|
|
||||||
/// 從一個節點陣列當中取出目前的索引鍵陣列。
|
/// 從一個節點陣列當中取出目前的索引鍵陣列。
|
||||||
public var keys: [String] { map(\.key) }
|
public func joinedKeys(by separator: String = Megrez.Compositor.theSeparator) -> [String] {
|
||||||
|
map { $0.keyArray.lazy.joined(separator: separator) }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 從一個節點陣列當中取出目前的索引鍵陣列。
|
||||||
|
public var keyArrays: [[String]] { map(\.keyArray) }
|
||||||
|
|
||||||
/// 返回一連串的節點起點。結果為 (Result A, Result B) 辭典陣列
|
/// 返回一連串的節點起點。結果為 (Result A, Result B) 辭典陣列
|
||||||
/// Result A 以索引查座標,Result B 以座標查索引。
|
/// Result A 以索引查座標,Result B 以座標查索引。
|
||||||
|
|
|
@ -5,10 +5,10 @@
|
||||||
|
|
||||||
/// 語言模組協定。
|
/// 語言模組協定。
|
||||||
public protocol LangModelProtocol {
|
public protocol LangModelProtocol {
|
||||||
/// 給定鍵,讓語言模型找給一組單元圖陣列。
|
/// 給定鍵陣列,讓語言模型找給一組單元圖陣列。
|
||||||
func unigramsFor(key: String) -> [Megrez.Unigram]
|
func unigramsFor(keyArray: [String]) -> [Megrez.Unigram]
|
||||||
/// 給定鍵,確認是否有單元圖記錄在庫。
|
/// 給定鍵陣列,確認是否有單元圖記錄在庫。
|
||||||
func hasUnigramsFor(key: String) -> Bool
|
func hasUnigramsFor(keyArray: [String]) -> Bool
|
||||||
}
|
}
|
||||||
|
|
||||||
extension Megrez.Compositor {
|
extension Megrez.Compositor {
|
||||||
|
@ -24,15 +24,15 @@ extension Megrez.Compositor {
|
||||||
/// 給定索引鍵,讓語言模型找給一組經過穩定排序的單元圖陣列。
|
/// 給定索引鍵,讓語言模型找給一組經過穩定排序的單元圖陣列。
|
||||||
/// - Parameter key: 給定的索引鍵字串。
|
/// - Parameter key: 給定的索引鍵字串。
|
||||||
/// - Returns: 對應的經過穩定排序的單元圖陣列。
|
/// - Returns: 對應的經過穩定排序的單元圖陣列。
|
||||||
public func unigramsFor(key: String) -> [Megrez.Unigram] {
|
public func unigramsFor(keyArray: [String]) -> [Megrez.Unigram] {
|
||||||
langModel.unigramsFor(key: key).stableSorted { $0.score > $1.score }
|
langModel.unigramsFor(keyArray: keyArray).stableSorted { $0.score > $1.score }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 根據給定的索引鍵來確認各個資料庫陣列內是否存在對應的資料。
|
/// 根據給定的索引鍵來確認各個資料庫陣列內是否存在對應的資料。
|
||||||
/// - Parameter key: 索引鍵。
|
/// - Parameter key: 索引鍵。
|
||||||
/// - Returns: 是否在庫。
|
/// - Returns: 是否在庫。
|
||||||
public func hasUnigramsFor(key: String) -> Bool {
|
public func hasUnigramsFor(keyArray: [String]) -> Bool {
|
||||||
langModel.hasUnigramsFor(key: key)
|
langModel.hasUnigramsFor(keyArray: keyArray)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,16 +25,16 @@ class SimpleLM: LangModelProtocol {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func unigramsFor(key: String) -> [Megrez.Unigram] {
|
func unigramsFor(keyArray: [String]) -> [Megrez.Unigram] {
|
||||||
if let f = mutDatabase[key] {
|
if let f = mutDatabase[keyArray.joined()] {
|
||||||
return f
|
return f
|
||||||
} else {
|
} else {
|
||||||
return [Megrez.Unigram]().sorted { $0.score > $1.score }
|
return [Megrez.Unigram]().sorted { $0.score > $1.score }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func hasUnigramsFor(key: String) -> Bool {
|
func hasUnigramsFor(keyArray: [String]) -> Bool {
|
||||||
mutDatabase.keys.contains(key)
|
mutDatabase.keys.contains(keyArray.joined())
|
||||||
}
|
}
|
||||||
|
|
||||||
func trim(key: String, value: String) {
|
func trim(key: String, value: String) {
|
||||||
|
@ -46,12 +46,12 @@ class SimpleLM: LangModelProtocol {
|
||||||
}
|
}
|
||||||
|
|
||||||
class MockLM: LangModelProtocol {
|
class MockLM: LangModelProtocol {
|
||||||
func unigramsFor(key: String) -> [Megrez.Unigram] {
|
func unigramsFor(keyArray: [String]) -> [Megrez.Unigram] {
|
||||||
[Megrez.Unigram(value: key, score: -1)]
|
[Megrez.Unigram(value: keyArray.joined(), score: -1)]
|
||||||
}
|
}
|
||||||
|
|
||||||
func hasUnigramsFor(key: String) -> Bool {
|
func hasUnigramsFor(keyArray: [String]) -> Bool {
|
||||||
!key.isEmpty
|
!keyArray.isEmpty
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -12,9 +12,11 @@ final class MegrezTests: XCTestCase {
|
||||||
func testSpan() throws {
|
func testSpan() throws {
|
||||||
let langModel = SimpleLM(input: strSampleData)
|
let langModel = SimpleLM(input: strSampleData)
|
||||||
let span = Megrez.Compositor.Span()
|
let span = Megrez.Compositor.Span()
|
||||||
let n1 = Megrez.Compositor.Node(keyArray: ["gao1"], spanLength: 1, unigrams: langModel.unigramsFor(key: "gao1"))
|
let n1 = Megrez.Compositor.Node(
|
||||||
|
keyArray: ["gao1"], spanLength: 1, unigrams: langModel.unigramsFor(keyArray: ["gao1"])
|
||||||
|
)
|
||||||
let n3 = Megrez.Compositor.Node(
|
let n3 = Megrez.Compositor.Node(
|
||||||
keyArray: ["gao1ke1ji4"], spanLength: 3, unigrams: langModel.unigramsFor(key: "gao1ke1ji4")
|
keyArray: ["gao1ke1ji4"], spanLength: 3, unigrams: langModel.unigramsFor(keyArray: ["gao1ke1ji4"])
|
||||||
)
|
)
|
||||||
XCTAssertEqual(span.maxLength, 0)
|
XCTAssertEqual(span.maxLength, 0)
|
||||||
span.append(node: n1)
|
span.append(node: n1)
|
||||||
|
@ -50,19 +52,19 @@ final class MegrezTests: XCTestCase {
|
||||||
|
|
||||||
func testRankedLangModel() throws {
|
func testRankedLangModel() throws {
|
||||||
class TestLM: LangModelProtocol {
|
class TestLM: LangModelProtocol {
|
||||||
func hasUnigramsFor(key: String) -> Bool { key == "foo" }
|
func hasUnigramsFor(keyArray: [String]) -> Bool { keyArray == ["foo"] }
|
||||||
func unigramsFor(key: String) -> [Megrez.Unigram] {
|
func unigramsFor(keyArray: [String]) -> [Megrez.Unigram] {
|
||||||
key == "foo"
|
keyArray == ["foo"]
|
||||||
? [.init(value: "middle", score: -5), .init(value: "highest", score: -2), .init(value: "lowest", score: -10)]
|
? [.init(value: "middle", score: -5), .init(value: "highest", score: -2), .init(value: "lowest", score: -10)]
|
||||||
: .init()
|
: .init()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let lmRanked = Megrez.Compositor.LangModelRanked(withLM: TestLM())
|
let lmRanked = Megrez.Compositor.LangModelRanked(withLM: TestLM())
|
||||||
XCTAssertTrue(lmRanked.hasUnigramsFor(key: "foo"))
|
XCTAssertTrue(lmRanked.hasUnigramsFor(keyArray: ["foo"]))
|
||||||
XCTAssertFalse(lmRanked.hasUnigramsFor(key: "bar"))
|
XCTAssertFalse(lmRanked.hasUnigramsFor(keyArray: ["bar"]))
|
||||||
XCTAssertTrue(lmRanked.unigramsFor(key: "bar").isEmpty)
|
XCTAssertTrue(lmRanked.unigramsFor(keyArray: ["bar"]).isEmpty)
|
||||||
let unigrams = lmRanked.unigramsFor(key: "foo")
|
let unigrams = lmRanked.unigramsFor(keyArray: ["foo"])
|
||||||
XCTAssertEqual(unigrams.count, 3)
|
XCTAssertEqual(unigrams.count, 3)
|
||||||
XCTAssertEqual(unigrams[0].value, "highest")
|
XCTAssertEqual(unigrams[0].value, "highest")
|
||||||
XCTAssertEqual(unigrams[0].score, -2)
|
XCTAssertEqual(unigrams[0].score, -2)
|
||||||
|
@ -74,7 +76,7 @@ final class MegrezTests: XCTestCase {
|
||||||
|
|
||||||
func testCompositor_BasicTests() throws {
|
func testCompositor_BasicTests() throws {
|
||||||
var compositor = Megrez.Compositor(with: MockLM())
|
var compositor = Megrez.Compositor(with: MockLM())
|
||||||
XCTAssertEqual(compositor.separator, Megrez.Compositor.kDefaultSeparator)
|
XCTAssertEqual(compositor.separator, Megrez.Compositor.theSeparator)
|
||||||
XCTAssertEqual(compositor.cursor, 0)
|
XCTAssertEqual(compositor.cursor, 0)
|
||||||
XCTAssertEqual(compositor.length, 0)
|
XCTAssertEqual(compositor.length, 0)
|
||||||
|
|
||||||
|
@ -87,7 +89,7 @@ final class MegrezTests: XCTestCase {
|
||||||
print("fuckme")
|
print("fuckme")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
XCTAssertEqual(zeroNode.key, "a")
|
XCTAssertEqual(zeroNode.keyArray.joined(separator: compositor.separator), "a")
|
||||||
|
|
||||||
compositor.dropKey(direction: .rear)
|
compositor.dropKey(direction: .rear)
|
||||||
XCTAssertEqual(compositor.cursor, 0)
|
XCTAssertEqual(compositor.cursor, 0)
|
||||||
|
@ -97,9 +99,9 @@ final class MegrezTests: XCTestCase {
|
||||||
|
|
||||||
func testCompositor_InvalidOperations() throws {
|
func testCompositor_InvalidOperations() throws {
|
||||||
class TestLM: LangModelProtocol {
|
class TestLM: LangModelProtocol {
|
||||||
func hasUnigramsFor(key: String) -> Bool { key == "foo" }
|
func hasUnigramsFor(keyArray: [String]) -> Bool { keyArray == ["foo"] }
|
||||||
func unigramsFor(key: String) -> [Megrez.Unigram] {
|
func unigramsFor(keyArray: [String]) -> [Megrez.Unigram] {
|
||||||
key == "foo" ? [.init(value: "foo", score: -1)] : .init()
|
keyArray == ["foo"] ? [.init(value: "foo", score: -1)] : .init()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -146,14 +148,14 @@ final class MegrezTests: XCTestCase {
|
||||||
XCTAssertEqual(compositor.length, 3)
|
XCTAssertEqual(compositor.length, 3)
|
||||||
XCTAssertEqual(compositor.spans.count, 3)
|
XCTAssertEqual(compositor.spans.count, 3)
|
||||||
XCTAssertEqual(compositor.spans[0].maxLength, 3)
|
XCTAssertEqual(compositor.spans[0].maxLength, 3)
|
||||||
XCTAssertEqual(compositor.spans[0].nodeOf(length: 1)?.key, "a")
|
XCTAssertEqual(compositor.spans[0].nodeOf(length: 1)?.keyArray.joined(separator: compositor.separator), "a")
|
||||||
XCTAssertEqual(compositor.spans[0].nodeOf(length: 2)?.key, "a;b")
|
XCTAssertEqual(compositor.spans[0].nodeOf(length: 2)?.keyArray.joined(separator: compositor.separator), "a;b")
|
||||||
XCTAssertEqual(compositor.spans[0].nodeOf(length: 3)?.key, "a;b;c")
|
XCTAssertEqual(compositor.spans[0].nodeOf(length: 3)?.keyArray.joined(separator: compositor.separator), "a;b;c")
|
||||||
XCTAssertEqual(compositor.spans[1].maxLength, 2)
|
XCTAssertEqual(compositor.spans[1].maxLength, 2)
|
||||||
XCTAssertEqual(compositor.spans[1].nodeOf(length: 1)?.key, "b")
|
XCTAssertEqual(compositor.spans[1].nodeOf(length: 1)?.keyArray.joined(separator: compositor.separator), "b")
|
||||||
XCTAssertEqual(compositor.spans[1].nodeOf(length: 2)?.key, "b;c")
|
XCTAssertEqual(compositor.spans[1].nodeOf(length: 2)?.keyArray.joined(separator: compositor.separator), "b;c")
|
||||||
XCTAssertEqual(compositor.spans[2].maxLength, 1)
|
XCTAssertEqual(compositor.spans[2].maxLength, 1)
|
||||||
XCTAssertEqual(compositor.spans[2].nodeOf(length: 1)?.key, "c")
|
XCTAssertEqual(compositor.spans[2].nodeOf(length: 1)?.keyArray.joined(separator: compositor.separator), "c")
|
||||||
}
|
}
|
||||||
|
|
||||||
func testCompositor_SpanDeletionFromFront() throws {
|
func testCompositor_SpanDeletionFromFront() throws {
|
||||||
|
@ -168,10 +170,10 @@ final class MegrezTests: XCTestCase {
|
||||||
XCTAssertEqual(compositor.length, 2)
|
XCTAssertEqual(compositor.length, 2)
|
||||||
XCTAssertEqual(compositor.spans.count, 2)
|
XCTAssertEqual(compositor.spans.count, 2)
|
||||||
XCTAssertEqual(compositor.spans[0].maxLength, 2)
|
XCTAssertEqual(compositor.spans[0].maxLength, 2)
|
||||||
XCTAssertEqual(compositor.spans[0].nodeOf(length: 1)?.key, "a")
|
XCTAssertEqual(compositor.spans[0].nodeOf(length: 1)?.keyArray.joined(separator: compositor.separator), "a")
|
||||||
XCTAssertEqual(compositor.spans[0].nodeOf(length: 2)?.key, "a;b")
|
XCTAssertEqual(compositor.spans[0].nodeOf(length: 2)?.keyArray.joined(separator: compositor.separator), "a;b")
|
||||||
XCTAssertEqual(compositor.spans[1].maxLength, 1)
|
XCTAssertEqual(compositor.spans[1].maxLength, 1)
|
||||||
XCTAssertEqual(compositor.spans[1].nodeOf(length: 1)?.key, "b")
|
XCTAssertEqual(compositor.spans[1].nodeOf(length: 1)?.keyArray.joined(separator: compositor.separator), "b")
|
||||||
}
|
}
|
||||||
|
|
||||||
func testCompositor_SpanDeletionFromMiddle() throws {
|
func testCompositor_SpanDeletionFromMiddle() throws {
|
||||||
|
@ -187,10 +189,10 @@ final class MegrezTests: XCTestCase {
|
||||||
XCTAssertEqual(compositor.length, 2)
|
XCTAssertEqual(compositor.length, 2)
|
||||||
XCTAssertEqual(compositor.spans.count, 2)
|
XCTAssertEqual(compositor.spans.count, 2)
|
||||||
XCTAssertEqual(compositor.spans[0].maxLength, 2)
|
XCTAssertEqual(compositor.spans[0].maxLength, 2)
|
||||||
XCTAssertEqual(compositor.spans[0].nodeOf(length: 1)?.key, "a")
|
XCTAssertEqual(compositor.spans[0].nodeOf(length: 1)?.keyArray.joined(separator: compositor.separator), "a")
|
||||||
XCTAssertEqual(compositor.spans[0].nodeOf(length: 2)?.key, "a;c")
|
XCTAssertEqual(compositor.spans[0].nodeOf(length: 2)?.keyArray.joined(separator: compositor.separator), "a;c")
|
||||||
XCTAssertEqual(compositor.spans[1].maxLength, 1)
|
XCTAssertEqual(compositor.spans[1].maxLength, 1)
|
||||||
XCTAssertEqual(compositor.spans[1].nodeOf(length: 1)?.key, "c")
|
XCTAssertEqual(compositor.spans[1].nodeOf(length: 1)?.keyArray.joined(separator: compositor.separator), "c")
|
||||||
|
|
||||||
compositor.clear()
|
compositor.clear()
|
||||||
compositor.insertKey("a")
|
compositor.insertKey("a")
|
||||||
|
@ -203,10 +205,10 @@ final class MegrezTests: XCTestCase {
|
||||||
XCTAssertEqual(compositor.length, 2)
|
XCTAssertEqual(compositor.length, 2)
|
||||||
XCTAssertEqual(compositor.spans.count, 2)
|
XCTAssertEqual(compositor.spans.count, 2)
|
||||||
XCTAssertEqual(compositor.spans[0].maxLength, 2)
|
XCTAssertEqual(compositor.spans[0].maxLength, 2)
|
||||||
XCTAssertEqual(compositor.spans[0].nodeOf(length: 1)?.key, "a")
|
XCTAssertEqual(compositor.spans[0].nodeOf(length: 1)?.keyArray.joined(separator: compositor.separator), "a")
|
||||||
XCTAssertEqual(compositor.spans[0].nodeOf(length: 2)?.key, "a;c")
|
XCTAssertEqual(compositor.spans[0].nodeOf(length: 2)?.keyArray.joined(separator: compositor.separator), "a;c")
|
||||||
XCTAssertEqual(compositor.spans[1].maxLength, 1)
|
XCTAssertEqual(compositor.spans[1].maxLength, 1)
|
||||||
XCTAssertEqual(compositor.spans[1].nodeOf(length: 1)?.key, "c")
|
XCTAssertEqual(compositor.spans[1].nodeOf(length: 1)?.keyArray.joined(separator: compositor.separator), "c")
|
||||||
}
|
}
|
||||||
|
|
||||||
func testCompositor_SpanDeletionFromRear() throws {
|
func testCompositor_SpanDeletionFromRear() throws {
|
||||||
|
@ -223,10 +225,10 @@ final class MegrezTests: XCTestCase {
|
||||||
XCTAssertEqual(compositor.length, 2)
|
XCTAssertEqual(compositor.length, 2)
|
||||||
XCTAssertEqual(compositor.spans.count, 2)
|
XCTAssertEqual(compositor.spans.count, 2)
|
||||||
XCTAssertEqual(compositor.spans[0].maxLength, 2)
|
XCTAssertEqual(compositor.spans[0].maxLength, 2)
|
||||||
XCTAssertEqual(compositor.spans[0].nodeOf(length: 1)?.key, "b")
|
XCTAssertEqual(compositor.spans[0].nodeOf(length: 1)?.keyArray.joined(separator: compositor.separator), "b")
|
||||||
XCTAssertEqual(compositor.spans[0].nodeOf(length: 2)?.key, "b;c")
|
XCTAssertEqual(compositor.spans[0].nodeOf(length: 2)?.keyArray.joined(separator: compositor.separator), "b;c")
|
||||||
XCTAssertEqual(compositor.spans[1].maxLength, 1)
|
XCTAssertEqual(compositor.spans[1].maxLength, 1)
|
||||||
XCTAssertEqual(compositor.spans[1].nodeOf(length: 1)?.key, "c")
|
XCTAssertEqual(compositor.spans[1].nodeOf(length: 1)?.keyArray.joined(separator: compositor.separator), "c")
|
||||||
}
|
}
|
||||||
|
|
||||||
func testCompositor_SpanInsertion() throws {
|
func testCompositor_SpanInsertion() throws {
|
||||||
|
@ -242,19 +244,19 @@ final class MegrezTests: XCTestCase {
|
||||||
XCTAssertEqual(compositor.length, 4)
|
XCTAssertEqual(compositor.length, 4)
|
||||||
XCTAssertEqual(compositor.spans.count, 4)
|
XCTAssertEqual(compositor.spans.count, 4)
|
||||||
XCTAssertEqual(compositor.spans[0].maxLength, 4)
|
XCTAssertEqual(compositor.spans[0].maxLength, 4)
|
||||||
XCTAssertEqual(compositor.spans[0].nodeOf(length: 1)?.key, "a")
|
XCTAssertEqual(compositor.spans[0].nodeOf(length: 1)?.keyArray.joined(separator: compositor.separator), "a")
|
||||||
XCTAssertEqual(compositor.spans[0].nodeOf(length: 2)?.key, "a;X")
|
XCTAssertEqual(compositor.spans[0].nodeOf(length: 2)?.keyArray.joined(separator: compositor.separator), "a;X")
|
||||||
XCTAssertEqual(compositor.spans[0].nodeOf(length: 3)?.key, "a;X;b")
|
XCTAssertEqual(compositor.spans[0].nodeOf(length: 3)?.keyArray.joined(separator: compositor.separator), "a;X;b")
|
||||||
XCTAssertEqual(compositor.spans[0].nodeOf(length: 4)?.key, "a;X;b;c")
|
XCTAssertEqual(compositor.spans[0].nodeOf(length: 4)?.keyArray.joined(separator: compositor.separator), "a;X;b;c")
|
||||||
XCTAssertEqual(compositor.spans[1].maxLength, 3)
|
XCTAssertEqual(compositor.spans[1].maxLength, 3)
|
||||||
XCTAssertEqual(compositor.spans[1].nodeOf(length: 1)?.key, "X")
|
XCTAssertEqual(compositor.spans[1].nodeOf(length: 1)?.keyArray.joined(separator: compositor.separator), "X")
|
||||||
XCTAssertEqual(compositor.spans[1].nodeOf(length: 2)?.key, "X;b")
|
XCTAssertEqual(compositor.spans[1].nodeOf(length: 2)?.keyArray.joined(separator: compositor.separator), "X;b")
|
||||||
XCTAssertEqual(compositor.spans[1].nodeOf(length: 3)?.key, "X;b;c")
|
XCTAssertEqual(compositor.spans[1].nodeOf(length: 3)?.keyArray.joined(separator: compositor.separator), "X;b;c")
|
||||||
XCTAssertEqual(compositor.spans[2].maxLength, 2)
|
XCTAssertEqual(compositor.spans[2].maxLength, 2)
|
||||||
XCTAssertEqual(compositor.spans[2].nodeOf(length: 1)?.key, "b")
|
XCTAssertEqual(compositor.spans[2].nodeOf(length: 1)?.keyArray.joined(separator: compositor.separator), "b")
|
||||||
XCTAssertEqual(compositor.spans[2].nodeOf(length: 2)?.key, "b;c")
|
XCTAssertEqual(compositor.spans[2].nodeOf(length: 2)?.keyArray.joined(separator: compositor.separator), "b;c")
|
||||||
XCTAssertEqual(compositor.spans[3].maxLength, 1)
|
XCTAssertEqual(compositor.spans[3].maxLength, 1)
|
||||||
XCTAssertEqual(compositor.spans[3].nodeOf(length: 1)?.key, "c")
|
XCTAssertEqual(compositor.spans[3].nodeOf(length: 1)?.keyArray.joined(separator: compositor.separator), "c")
|
||||||
}
|
}
|
||||||
|
|
||||||
func testCompositor_LongGridDeletion() throws {
|
func testCompositor_LongGridDeletion() throws {
|
||||||
|
@ -279,17 +281,17 @@ final class MegrezTests: XCTestCase {
|
||||||
XCTAssertEqual(compositor.cursor, 6)
|
XCTAssertEqual(compositor.cursor, 6)
|
||||||
XCTAssertEqual(compositor.length, 13)
|
XCTAssertEqual(compositor.length, 13)
|
||||||
XCTAssertEqual(compositor.spans.count, 13)
|
XCTAssertEqual(compositor.spans.count, 13)
|
||||||
XCTAssertEqual(compositor.spans[0].nodeOf(length: 6)?.key, "abcdef")
|
XCTAssertEqual(compositor.spans[0].nodeOf(length: 6)?.keyArray.joined(separator: compositor.separator), "abcdef")
|
||||||
XCTAssertEqual(compositor.spans[1].nodeOf(length: 6)?.key, "bcdefh")
|
XCTAssertEqual(compositor.spans[1].nodeOf(length: 6)?.keyArray.joined(separator: compositor.separator), "bcdefh")
|
||||||
XCTAssertEqual(compositor.spans[1].nodeOf(length: 5)?.key, "bcdef")
|
XCTAssertEqual(compositor.spans[1].nodeOf(length: 5)?.keyArray.joined(separator: compositor.separator), "bcdef")
|
||||||
XCTAssertEqual(compositor.spans[2].nodeOf(length: 6)?.key, "cdefhi")
|
XCTAssertEqual(compositor.spans[2].nodeOf(length: 6)?.keyArray.joined(separator: compositor.separator), "cdefhi")
|
||||||
XCTAssertEqual(compositor.spans[2].nodeOf(length: 5)?.key, "cdefh")
|
XCTAssertEqual(compositor.spans[2].nodeOf(length: 5)?.keyArray.joined(separator: compositor.separator), "cdefh")
|
||||||
XCTAssertEqual(compositor.spans[3].nodeOf(length: 6)?.key, "defhij")
|
XCTAssertEqual(compositor.spans[3].nodeOf(length: 6)?.keyArray.joined(separator: compositor.separator), "defhij")
|
||||||
XCTAssertEqual(compositor.spans[4].nodeOf(length: 6)?.key, "efhijk")
|
XCTAssertEqual(compositor.spans[4].nodeOf(length: 6)?.keyArray.joined(separator: compositor.separator), "efhijk")
|
||||||
XCTAssertEqual(compositor.spans[5].nodeOf(length: 6)?.key, "fhijkl")
|
XCTAssertEqual(compositor.spans[5].nodeOf(length: 6)?.keyArray.joined(separator: compositor.separator), "fhijkl")
|
||||||
XCTAssertEqual(compositor.spans[6].nodeOf(length: 6)?.key, "hijklm")
|
XCTAssertEqual(compositor.spans[6].nodeOf(length: 6)?.keyArray.joined(separator: compositor.separator), "hijklm")
|
||||||
XCTAssertEqual(compositor.spans[7].nodeOf(length: 6)?.key, "ijklmn")
|
XCTAssertEqual(compositor.spans[7].nodeOf(length: 6)?.keyArray.joined(separator: compositor.separator), "ijklmn")
|
||||||
XCTAssertEqual(compositor.spans[8].nodeOf(length: 5)?.key, "jklmn")
|
XCTAssertEqual(compositor.spans[8].nodeOf(length: 5)?.keyArray.joined(separator: compositor.separator), "jklmn")
|
||||||
}
|
}
|
||||||
|
|
||||||
func testCompositor_LongGridInsertion() throws {
|
func testCompositor_LongGridInsertion() throws {
|
||||||
|
@ -314,19 +316,19 @@ final class MegrezTests: XCTestCase {
|
||||||
XCTAssertEqual(compositor.cursor, 8)
|
XCTAssertEqual(compositor.cursor, 8)
|
||||||
XCTAssertEqual(compositor.length, 15)
|
XCTAssertEqual(compositor.length, 15)
|
||||||
XCTAssertEqual(compositor.spans.count, 15)
|
XCTAssertEqual(compositor.spans.count, 15)
|
||||||
XCTAssertEqual(compositor.spans[0].nodeOf(length: 6)?.key, "abcdef")
|
XCTAssertEqual(compositor.spans[0].nodeOf(length: 6)?.keyArray.joined(separator: compositor.separator), "abcdef")
|
||||||
XCTAssertEqual(compositor.spans[1].nodeOf(length: 6)?.key, "bcdefg")
|
XCTAssertEqual(compositor.spans[1].nodeOf(length: 6)?.keyArray.joined(separator: compositor.separator), "bcdefg")
|
||||||
XCTAssertEqual(compositor.spans[2].nodeOf(length: 6)?.key, "cdefgX")
|
XCTAssertEqual(compositor.spans[2].nodeOf(length: 6)?.keyArray.joined(separator: compositor.separator), "cdefgX")
|
||||||
XCTAssertEqual(compositor.spans[3].nodeOf(length: 6)?.key, "defgXh")
|
XCTAssertEqual(compositor.spans[3].nodeOf(length: 6)?.keyArray.joined(separator: compositor.separator), "defgXh")
|
||||||
XCTAssertEqual(compositor.spans[3].nodeOf(length: 5)?.key, "defgX")
|
XCTAssertEqual(compositor.spans[3].nodeOf(length: 5)?.keyArray.joined(separator: compositor.separator), "defgX")
|
||||||
XCTAssertEqual(compositor.spans[4].nodeOf(length: 6)?.key, "efgXhi")
|
XCTAssertEqual(compositor.spans[4].nodeOf(length: 6)?.keyArray.joined(separator: compositor.separator), "efgXhi")
|
||||||
XCTAssertEqual(compositor.spans[4].nodeOf(length: 5)?.key, "efgXh")
|
XCTAssertEqual(compositor.spans[4].nodeOf(length: 5)?.keyArray.joined(separator: compositor.separator), "efgXh")
|
||||||
XCTAssertEqual(compositor.spans[4].nodeOf(length: 4)?.key, "efgX")
|
XCTAssertEqual(compositor.spans[4].nodeOf(length: 4)?.keyArray.joined(separator: compositor.separator), "efgX")
|
||||||
XCTAssertEqual(compositor.spans[4].nodeOf(length: 3)?.key, "efg")
|
XCTAssertEqual(compositor.spans[4].nodeOf(length: 3)?.keyArray.joined(separator: compositor.separator), "efg")
|
||||||
XCTAssertEqual(compositor.spans[5].nodeOf(length: 6)?.key, "fgXhij")
|
XCTAssertEqual(compositor.spans[5].nodeOf(length: 6)?.keyArray.joined(separator: compositor.separator), "fgXhij")
|
||||||
XCTAssertEqual(compositor.spans[6].nodeOf(length: 6)?.key, "gXhijk")
|
XCTAssertEqual(compositor.spans[6].nodeOf(length: 6)?.keyArray.joined(separator: compositor.separator), "gXhijk")
|
||||||
XCTAssertEqual(compositor.spans[7].nodeOf(length: 6)?.key, "Xhijkl")
|
XCTAssertEqual(compositor.spans[7].nodeOf(length: 6)?.keyArray.joined(separator: compositor.separator), "Xhijkl")
|
||||||
XCTAssertEqual(compositor.spans[8].nodeOf(length: 6)?.key, "hijklm")
|
XCTAssertEqual(compositor.spans[8].nodeOf(length: 6)?.keyArray.joined(separator: compositor.separator), "hijklm")
|
||||||
}
|
}
|
||||||
|
|
||||||
func testCompositor_StressBench() throws {
|
func testCompositor_StressBench() throws {
|
||||||
|
@ -349,7 +351,7 @@ final class MegrezTests: XCTestCase {
|
||||||
compositor.insertKey(String(i))
|
compositor.insertKey(String(i))
|
||||||
}
|
}
|
||||||
let result = compositor.walk().0
|
let result = compositor.walk().0
|
||||||
XCTAssertEqual(result.keys, ["高科技", "公司", "的", "年終", "獎金"])
|
XCTAssertEqual(result.joinedKeys(by: ""), ["高科技", "公司", "的", "年終", "獎金"])
|
||||||
}
|
}
|
||||||
|
|
||||||
func testCompositor_InputTestAndCursorJump() throws {
|
func testCompositor_InputTestAndCursorJump() throws {
|
||||||
|
@ -510,11 +512,11 @@ final class MegrezTests: XCTestCase {
|
||||||
XCTAssertEqual(result.values, ["高熱", "火焰", "危險"])
|
XCTAssertEqual(result.values, ["高熱", "火焰", "危險"])
|
||||||
let location = 2
|
let location = 2
|
||||||
|
|
||||||
XCTAssertTrue(compositor.overrideCandidate(.init(key: "huo3", value: "🔥"), at: location))
|
XCTAssertTrue(compositor.overrideCandidate(.init(keyArray: ["huo3"], value: "🔥"), at: location))
|
||||||
result = compositor.walk().0
|
result = compositor.walk().0
|
||||||
XCTAssertEqual(result.values, ["高熱", "🔥", "焰", "危險"])
|
XCTAssertEqual(result.values, ["高熱", "🔥", "焰", "危險"])
|
||||||
|
|
||||||
XCTAssertTrue(compositor.overrideCandidate(.init(key: "huo3yan4", value: "🔥"), at: location))
|
XCTAssertTrue(compositor.overrideCandidate(.init(keyArray: ["huo3", "yan4"], value: "🔥"), at: location))
|
||||||
result = compositor.walk().0
|
result = compositor.walk().0
|
||||||
XCTAssertEqual(result.values, ["高熱", "🔥", "危險"])
|
XCTAssertEqual(result.values, ["高熱", "🔥", "危險"])
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue