From ba4654f850e627d07687a5a5cbe38fb18ac2f4ba Mon Sep 17 00:00:00 2001 From: ShikiSuen Date: Tue, 31 May 2022 23:43:06 +0800 Subject: [PATCH] Megrez v1.1.9 // Real forwardWalker(). - Also, Grid: Get [NodeAnchor] using given ClosedRange. --- .../Megrez/1_BlockReadingBuilder.swift | 101 ++++++++++++++++-- .../LanguageParsers/Megrez/2_Grid.swift | 63 +++++++++-- 2 files changed, 152 insertions(+), 12 deletions(-) diff --git a/Source/Modules/LanguageParsers/Megrez/1_BlockReadingBuilder.swift b/Source/Modules/LanguageParsers/Megrez/1_BlockReadingBuilder.swift index c8f5f1e4..a45f8e96 100644 --- a/Source/Modules/LanguageParsers/Megrez/1_BlockReadingBuilder.swift +++ b/Source/Modules/LanguageParsers/Megrez/1_BlockReadingBuilder.swift @@ -147,12 +147,101 @@ extension Megrez { joinedPhrase: String = "", longPhrases: [String] = .init() ) -> [NodeAnchor] { - let newLocation = (mutGrid.width) - abs(location) // 防呆 - return Array( - reverseWalk( - at: newLocation, score: accumulatedScore, - joinedPhrase: joinedPhrase, longPhrases: longPhrases - ).reversed()) + let location = abs(location) // 防呆 + if location >= mutGrid.width { + return .init() + } + + var paths = [[NodeAnchor]]() + var nodes = mutGrid.nodesBeginningAt(location: location) + + nodes = nodes.stableSorted { + $0.scoreForSort > $1.scoreForSort + } + + if let nodeOfNodeZero = nodes[0].node, nodeOfNodeZero.score >= nodeOfNodeZero.kSelectedCandidateScore { + // 在使用者有選過候選字詞的情況下,摒棄非依此據而成的節點路徑。 + var nodeZero = nodes[0] + nodeZero.accumulatedScore = accumulatedScore + nodeOfNodeZero.score + var path: [NodeAnchor] = walk(at: location + nodeZero.spanningLength, score: nodeZero.accumulatedScore) + path.insert(nodeZero, at: 0) + paths.append(path) + } else if !longPhrases.isEmpty { + var path = [NodeAnchor]() + for theAnchor in nodes { + guard let theNode = theAnchor.node else { continue } + var theAnchor = theAnchor + let joinedValue = joinedPhrase + theNode.currentKeyValue.value + // 如果只是一堆單漢字的節點組成了同樣的長詞的話,直接棄用這個節點路徑。 + // 打比方說「八/月/中/秋/山/林/涼」與「八月/中秋/山林/涼」在使用者來看 + // 是「結果等價」的,那就扔掉前者。 + if longPhrases.contains(joinedValue) { + theAnchor.accumulatedScore = kDroppedPathScore + path.insert(theAnchor, at: 0) + paths.append(path) + continue + } + theAnchor.accumulatedScore = accumulatedScore + theNode.score + if joinedValue.count >= longPhrases[0].count { + path = walk( + at: location + theAnchor.spanningLength, score: theAnchor.accumulatedScore, joinedPhrase: "", + longPhrases: .init() + ) + } else { + path = walk( + at: location + theAnchor.spanningLength, score: theAnchor.accumulatedScore, joinedPhrase: joinedValue, + longPhrases: longPhrases + ) + } + path.insert(theAnchor, at: 0) + paths.append(path) + } + } else { + // 看看當前格位有沒有更長的候選字詞。 + var longPhrases = [String]() + for theAnchor in nodes { + guard let theNode = theAnchor.node else { continue } + if theAnchor.spanningLength > 1 { + longPhrases.append(theNode.currentKeyValue.value) + } + } + + longPhrases = longPhrases.stableSorted { + $0.count > $1.count + } + for theAnchor in nodes { + var theAnchor = theAnchor + guard let theNode = theAnchor.node else { continue } + theAnchor.accumulatedScore = accumulatedScore + theNode.score + var path = [NodeAnchor]() + if theAnchor.spanningLength > 1 { + path = walk( + at: location + theAnchor.spanningLength, score: theAnchor.accumulatedScore, joinedPhrase: "", + longPhrases: .init() + ) + } else { + path = walk( + at: location + 1, score: theAnchor.accumulatedScore, + joinedPhrase: theNode.currentKeyValue.value, longPhrases: longPhrases + ) + } + path.insert(theAnchor, at: 0) + paths.append(path) + } + } + + guard !paths.isEmpty else { + return .init() + } + + var result: [NodeAnchor] = paths[0] + for neta in paths { + if neta.last!.accumulatedScore > result.last!.accumulatedScore { + result = neta + } + } + + return result } /// 對已給定的軌格按照給定的位置與條件進行反向爬軌。 diff --git a/Source/Modules/LanguageParsers/Megrez/2_Grid.swift b/Source/Modules/LanguageParsers/Megrez/2_Grid.swift index 3eec69ba..e7ac18c7 100644 --- a/Source/Modules/LanguageParsers/Megrez/2_Grid.swift +++ b/Source/Modules/LanguageParsers/Megrez/2_Grid.swift @@ -189,14 +189,43 @@ extension Megrez { return results } + /// 獲取給定的範圍內的節點,以節錨為單位來獲取一個結果陣列。 + /// - Parameters: + /// - range: 給定首尾範圍,必須得是閉區間。 + func nodes(in range: ClosedRange) -> [NodeAnchor] { + var result = [NodeAnchor]() + if !mutSpans.isEmpty, range.upperBound <= mutSpans.count { + for i in 0.. range.lowerBound { + for j in 1...span.maximumLength { + guard let np = span.node(length: j), + (i + j) > range.lowerBound + else { continue } + result.append( + NodeAnchor( + node: np, + location: i, + spanningLength: j + ) + ) + } + } + } + } + return result + } + /// 將給定位置的節點的候選字詞改為與給定的字串一致的候選字詞。 /// - Parameters: /// - location: 位置。 /// - value: 給定字串。 @discardableResult public func fixNodeSelectedCandidate(location: Int, value: String) -> NodeAnchor { let location = abs(location) // 防呆 - var node = NodeAnchor() - for nodeAnchor in nodesCrossingOrEndingAt(location: location) { + var anchor = NodeAnchor() + var selectedIndex = 0 + var anchors = nodesCrossingOrEndingAt(location: location) + for nodeAnchor in anchors { guard let theNode = nodeAnchor.node else { continue } @@ -205,13 +234,24 @@ extension Megrez { theNode.resetCandidate() for (i, candidate) in candidates.enumerated() { if candidate.value == value { - theNode.selectCandidateAt(index: i) - node = nodeAnchor + selectedIndex = i + anchor = nodeAnchor break } } } - return node + guard let node = anchor.node else { + return anchor + } + anchors = nodes(in: (location - anchor.spanningLength)...location) + for nodeAnchor in anchors { + if let theNode = nodeAnchor.node { + theNode.resetCandidate() + } + } + node.selectCandidateAt(index: selectedIndex) + anchor.node = node + return anchor } /// 將給定位置的節點的與給定的字串一致的候選字詞的權重複寫為給定權重數值。 @@ -221,7 +261,10 @@ extension Megrez { /// - overridingScore: 給定權重數值。 public func overrideNodeScoreForSelectedCandidate(location: Int, value: String, overridingScore: Double) { let location = abs(location) // 防呆 - for nodeAnchor in nodesCrossingOrEndingAt(location: location) { + let anchor = NodeAnchor() + let selectedIndex = 0 + var anchors = nodesCrossingOrEndingAt(location: location) + for nodeAnchor in anchors { guard let theNode = nodeAnchor.node else { continue } @@ -235,6 +278,14 @@ extension Megrez { } } } + guard let node = anchor.node else { return } + anchors = nodes(in: (location - anchor.spanningLength)...location) + for nodeAnchor in anchors { + if let theNode = nodeAnchor.node { + theNode.resetCandidate() + } + } + node.selectFloatingCandidateAt(index: selectedIndex, score: overridingScore) } } }