refactor: clean up API

This commit is contained in:
ensan-hcl
2025-07-15 05:02:29 +09:00
parent 814a6b080b
commit b9bd88a247
5 changed files with 55 additions and 46 deletions

View File

@ -35,14 +35,19 @@ extension Kana2Kanji {
let indexMap = LatticeDualIndexMap(inputData) let indexMap = LatticeDualIndexMap(inputData)
let latticeIndices = indexMap.indices(inputCount: inputCount, surfaceCount: surfaceCount) let latticeIndices = indexMap.indices(inputCount: inputCount, surfaceCount: surfaceCount)
let rawNodes = latticeIndices.map { index in let rawNodes = latticeIndices.map { index in
let inputRange: (startIndex: Int, endIndexRange: Range<Int>?)? = if let iIndex = index.inputIndex {
(iIndex, nil)
} else {
nil
}
let surfaceRange: (startIndex: Int, endIndexRange: Range<Int>?)? = if let sIndex = index.surfaceIndex { let surfaceRange: (startIndex: Int, endIndexRange: Range<Int>?)? = if let sIndex = index.surfaceIndex {
(sIndex, nil) (sIndex, nil)
} else { } else {
nil nil
} }
return dicdataStore.getLOUDSDataInRange( return dicdataStore.lookupDicdata(
inputData: inputData, composingText: inputData,
from: index.inputIndex, inputRange: inputRange,
surfaceRange: surfaceRange, surfaceRange: surfaceRange,
needTypoCorrection: needTypoCorrection needTypoCorrection: needTypoCorrection
) )

View File

@ -27,14 +27,19 @@ extension Kana2Kanji {
let indexMap = LatticeDualIndexMap(inputData) let indexMap = LatticeDualIndexMap(inputData)
let latticeIndices = indexMap.indices(inputCount: inputCount, surfaceCount: surfaceCount) let latticeIndices = indexMap.indices(inputCount: inputCount, surfaceCount: surfaceCount)
let rawNodes = latticeIndices.map { index in let rawNodes = latticeIndices.map { index in
let inputRange: (startIndex: Int, endIndexRange: Range<Int>?)? = if let iIndex = index.inputIndex {
(iIndex, nil)
} else {
nil
}
let surfaceRange: (startIndex: Int, endIndexRange: Range<Int>?)? = if let sIndex = index.surfaceIndex { let surfaceRange: (startIndex: Int, endIndexRange: Range<Int>?)? = if let sIndex = index.surfaceIndex {
(sIndex, nil) (sIndex, nil)
} else { } else {
nil nil
} }
return dicdataStore.getLOUDSDataInRange( return dicdataStore.lookupDicdata(
inputData: inputData, composingText: inputData,
from: index.inputIndex, inputRange: inputRange,
surfaceRange: surfaceRange, surfaceRange: surfaceRange,
needTypoCorrection: false needTypoCorrection: false
) )

View File

@ -68,10 +68,9 @@ extension Kana2Kanji {
} else { } else {
nil nil
} }
return self.dicdataStore.getLOUDSDataInRange( return self.dicdataStore.lookupDicdata(
inputData: inputData, composingText: inputData,
from: inputRange?.startIndex, inputRange: inputRange,
toIndexRange: inputRange?.endIndexRange,
surfaceRange: surfaceRange, surfaceRange: surfaceRange,
needTypoCorrection: needTypoCorrection needTypoCorrection: needTypoCorrection
) )

View File

@ -465,33 +465,33 @@ public final class DicdataStore {
} }
return data return data
} }
/// kana2lattice ///
/// - Parameters: /// - Parameters:
/// - inputData: /// - composingText:
/// - from: /// - inputRange: `composingText.input`
/// - toIndexRange: `from ..< (toIndexRange)` /// - surfaceRange: `composingText.convertTarget`
public func getLOUDSDataInRange( /// - needTypoCorrection:
inputData: ComposingText, /// - Returns: `LatticeNode`
from fromInputIndex: Int?, public func lookupDicdata(
toIndexRange: Range<Int>? = nil, composingText: ComposingText,
inputRange:(startIndex: Int, endIndexRange: Range<Int>?)? = nil,
surfaceRange: (startIndex: Int, endIndexRange: Range<Int>?)? = nil, surfaceRange: (startIndex: Int, endIndexRange: Range<Int>?)? = nil,
needTypoCorrection: Bool = true needTypoCorrection: Bool = true
) -> [LatticeNode] { ) -> [LatticeNode] {
let inputProcessRange: TypoCorrectionGenerator.ProcessRange?
// TODO: make `fromInputIndex` optional later. let inputProcessRange: TypoCorrectionGenerator.ProcessRange?
if let fromInputIndex { if let inputRange {
let toInputIndexLeft = toIndexRange?.startIndex ?? fromInputIndex let toInputIndexLeft = inputRange.endIndexRange?.startIndex ?? inputRange.startIndex
let toInputIndexRight = min( let toInputIndexRight = min(
toIndexRange?.endIndex ?? inputData.input.count, inputRange.endIndexRange?.endIndex ?? composingText.input.count,
fromInputIndex + self.maxlength inputRange.startIndex + self.maxlength
) )
if fromInputIndex > toInputIndexLeft || toInputIndexLeft >= toInputIndexRight { if inputRange.startIndex > toInputIndexLeft || toInputIndexLeft >= toInputIndexRight {
debug(#function, "index is wrong") debug(#function, "index is wrong")
return [] return []
} }
inputProcessRange = .init(leftIndex: fromInputIndex, rightIndexRange: toInputIndexLeft ..< toInputIndexRight) inputProcessRange = .init(leftIndex: inputRange.startIndex, rightIndexRange: toInputIndexLeft ..< toInputIndexRight)
} else { } else {
inputProcessRange = nil inputProcessRange = nil
} }
@ -500,7 +500,7 @@ public final class DicdataStore {
if let surfaceRange { if let surfaceRange {
let toSurfaceIndexLeft = surfaceRange.endIndexRange?.startIndex ?? surfaceRange.startIndex let toSurfaceIndexLeft = surfaceRange.endIndexRange?.startIndex ?? surfaceRange.startIndex
let toSurfaceIndexRight = min( let toSurfaceIndexRight = min(
surfaceRange.endIndexRange?.endIndex ?? inputData.convertTarget.count, surfaceRange.endIndexRange?.endIndex ?? composingText.convertTarget.count,
surfaceRange.startIndex + self.maxlength surfaceRange.startIndex + self.maxlength
) )
if surfaceRange.startIndex > toSurfaceIndexLeft || toSurfaceIndexLeft >= toSurfaceIndexRight { if surfaceRange.startIndex > toSurfaceIndexLeft || toSurfaceIndexLeft >= toSurfaceIndexRight {
@ -517,7 +517,7 @@ public final class DicdataStore {
} }
// MARK: // MARK:
var (stringToInfo, indices, dicdata) = self.movingTowardPrefixSearch( var (stringToInfo, indices, dicdata) = self.movingTowardPrefixSearch(
composingText: inputData, composingText: composingText,
inputProcessRange: inputProcessRange, inputProcessRange: inputProcessRange,
surfaceProcessRange: surfaceProcessRange, surfaceProcessRange: surfaceProcessRange,
useMemory: self.learningManager.enabled, useMemory: self.learningManager.enabled,
@ -544,13 +544,13 @@ public final class DicdataStore {
if let inputProcessRange { if let inputProcessRange {
let segments = (inputProcessRange.leftIndex ..< inputProcessRange.rightIndexRange.endIndex).reduce(into: []) { (segments: inout [String], rightIndex: Int) in let segments = (inputProcessRange.leftIndex ..< inputProcessRange.rightIndexRange.endIndex).reduce(into: []) { (segments: inout [String], rightIndex: Int) in
segments.append((segments.last ?? "") + String(inputData.input[rightIndex].character.toKatakana())) segments.append((segments.last ?? "") + String(composingText.input[rightIndex].character.toKatakana()))
} }
for i in inputProcessRange.rightIndexRange { for i in inputProcessRange.rightIndexRange {
do { do {
let result = self.getWiseDicdata( let result = self.getWiseDicdata(
convertTarget: segments[i - inputProcessRange.leftIndex], convertTarget: segments[i - inputProcessRange.leftIndex],
inputData: inputData, inputData: composingText,
inputRange: inputProcessRange.leftIndex ..< i + 1 inputRange: inputProcessRange.leftIndex ..< i + 1
) )
for item in result { for item in result {
@ -560,13 +560,13 @@ public final class DicdataStore {
} }
} }
} }
let needBOS = fromInputIndex == .zero let needBOS = inputRange?.startIndex == .zero || surfaceRange?.startIndex == .zero
let result: [LatticeNode] = dicdata.compactMap { let result: [LatticeNode] = dicdata.compactMap {
guard let endIndex = stringToInfo[Array($0.ruby)]?.endIndex else { guard let endIndex = stringToInfo[Array($0.ruby)]?.endIndex else {
return nil return nil
} }
let range: Lattice.LatticeRange = switch endIndex { let range: Lattice.LatticeRange = switch endIndex {
case .input(let endIndex): .input(from: fromInputIndex!, to: endIndex + 1) case .input(let endIndex): .input(from: (inputRange?.startIndex)!, to: endIndex + 1)
case .surface(let endIndex): .surface(from: (surfaceRange?.startIndex)!, to: endIndex + 1) case .surface(let endIndex): .surface(from: (surfaceRange?.startIndex)!, to: endIndex + 1)
} }
let node = LatticeNode(data: $0, range: range) let node = LatticeNode(data: $0, range: range)

View File

@ -129,7 +129,7 @@ final class DicdataStoreTests: XCTestCase {
for (key, word) in mustWords { for (key, word) in mustWords {
var c = ComposingText() var c = ComposingText()
c.insertAtCursorPosition(key, inputStyle: .direct) c.insertAtCursorPosition(key, inputStyle: .direct)
let result = dicdataStore.getLOUDSDataInRange(inputData: c, from: 0, toIndexRange: c.input.endIndex - 1 ..< c.input.endIndex, needTypoCorrection: false) let result = dicdataStore.lookupDicdata(composingText: c, inputRange: (0, c.input.endIndex - 1 ..< c.input.endIndex), needTypoCorrection: false)
// //
XCTAssertEqual(result.first(where: {$0.data.word == word})?.data.word, word) XCTAssertEqual(result.first(where: {$0.data.word == word})?.data.word, word)
} }
@ -150,7 +150,7 @@ final class DicdataStoreTests: XCTestCase {
for (key, word) in mustWords { for (key, word) in mustWords {
var c = ComposingText() var c = ComposingText()
c.insertAtCursorPosition(key, inputStyle: .direct) c.insertAtCursorPosition(key, inputStyle: .direct)
let result = dicdataStore.getLOUDSDataInRange(inputData: c, from: 0, toIndexRange: c.input.endIndex - 1 ..< c.input.endIndex, needTypoCorrection: false) let result = dicdataStore.lookupDicdata(composingText: c, inputRange: (0, c.input.endIndex - 1 ..< c.input.endIndex), needTypoCorrection: false)
XCTAssertNil(result.first(where: {$0.data.word == word && $0.data.ruby == key})) XCTAssertNil(result.first(where: {$0.data.word == word && $0.data.ruby == key}))
} }
} }
@ -170,17 +170,17 @@ final class DicdataStoreTests: XCTestCase {
for (key, word) in mustWords { for (key, word) in mustWords {
var c = ComposingText() var c = ComposingText()
c.insertAtCursorPosition(key, inputStyle: .direct) c.insertAtCursorPosition(key, inputStyle: .direct)
let result = dicdataStore.getLOUDSDataInRange(inputData: c, from: 0, toIndexRange: c.input.endIndex - 1 ..< c.input.endIndex, needTypoCorrection: true) let result = dicdataStore.lookupDicdata(composingText: c, inputRange: (0, c.input.endIndex - 1 ..< c.input.endIndex), needTypoCorrection: true)
XCTAssertEqual(result.first(where: {$0.data.word == word})?.data.word, word) XCTAssertEqual(result.first(where: {$0.data.word == word})?.data.word, word)
} }
} }
func testGetLOUDSDataInRange() throws { func testLookupDicdata() throws {
let dicdataStore = DicdataStore(convertRequestOptions: requestOptions()) let dicdataStore = DicdataStore(convertRequestOptions: requestOptions())
do { do {
var c = ComposingText() var c = ComposingText()
c.insertAtCursorPosition("ヘンカン", inputStyle: .roman2kana) c.insertAtCursorPosition("ヘンカン", inputStyle: .roman2kana)
let result = dicdataStore.getLOUDSDataInRange(inputData: c, from: 0, toIndexRange: 2..<4) let result = dicdataStore.lookupDicdata(composingText: c, inputRange: (0, 2 ..< 4))
XCTAssertFalse(result.contains(where: {$0.data.word == ""})) XCTAssertFalse(result.contains(where: {$0.data.word == ""}))
XCTAssertTrue(result.contains(where: {$0.data.word == "変化"})) XCTAssertTrue(result.contains(where: {$0.data.word == "変化"}))
XCTAssertTrue(result.contains(where: {$0.data.word == "変換"})) XCTAssertTrue(result.contains(where: {$0.data.word == "変換"}))
@ -188,7 +188,7 @@ final class DicdataStoreTests: XCTestCase {
do { do {
var c = ComposingText() var c = ComposingText()
c.insertAtCursorPosition("ヘンカン", inputStyle: .roman2kana) c.insertAtCursorPosition("ヘンカン", inputStyle: .roman2kana)
let result = dicdataStore.getLOUDSDataInRange(inputData: c, from: 0, toIndexRange: 0..<4) let result = dicdataStore.lookupDicdata(composingText: c, inputRange: (0, 0..<4))
XCTAssertTrue(result.contains(where: {$0.data.word == ""})) XCTAssertTrue(result.contains(where: {$0.data.word == ""}))
XCTAssertTrue(result.contains(where: {$0.data.word == "変化"})) XCTAssertTrue(result.contains(where: {$0.data.word == "変化"}))
XCTAssertTrue(result.contains(where: {$0.data.word == "変換"})) XCTAssertTrue(result.contains(where: {$0.data.word == "変換"}))
@ -196,19 +196,19 @@ final class DicdataStoreTests: XCTestCase {
do { do {
var c = ComposingText() var c = ComposingText()
c.insertAtCursorPosition("ツカッ", inputStyle: .roman2kana) c.insertAtCursorPosition("ツカッ", inputStyle: .roman2kana)
let result = dicdataStore.getLOUDSDataInRange(inputData: c, from: 0, toIndexRange: 2..<3) let result = dicdataStore.lookupDicdata(composingText: c, inputRange: (0, 2..<3))
XCTAssertTrue(result.contains(where: {$0.data.word == "使っ"})) XCTAssertTrue(result.contains(where: {$0.data.word == "使っ"}))
} }
do { do {
var c = ComposingText() var c = ComposingText()
c.insertAtCursorPosition("ツカッt", inputStyle: .roman2kana) c.insertAtCursorPosition("ツカッt", inputStyle: .roman2kana)
let result = dicdataStore.getLOUDSDataInRange(inputData: c, from: 0, toIndexRange: 2..<4) let result = dicdataStore.lookupDicdata(composingText: c, inputRange: (0, 2..<4))
XCTAssertTrue(result.contains(where: {$0.data.word == "使っ"})) XCTAssertTrue(result.contains(where: {$0.data.word == "使っ"}))
} }
do { do {
var c = ComposingText() var c = ComposingText()
sequentialInput(&c, sequence: "tukatt", inputStyle: .roman2kana) sequentialInput(&c, sequence: "tukatt", inputStyle: .roman2kana)
let result = dicdataStore.getLOUDSDataInRange(inputData: c, from: 0, toIndexRange: 4..<6) let result = dicdataStore.lookupDicdata(composingText: c, inputRange: (0, 4..<6))
XCTAssertTrue(result.contains(where: {$0.data.word == "使っ"})) XCTAssertTrue(result.contains(where: {$0.data.word == "使っ"}))
} }
} }
@ -255,7 +255,7 @@ final class DicdataStoreTests: XCTestCase {
do { do {
var c = ComposingText() var c = ComposingText()
c.insertAtCursorPosition("テストタンゴ", inputStyle: .direct) c.insertAtCursorPosition("テストタンゴ", inputStyle: .direct)
let result = dicdataStore.getLOUDSDataInRange(inputData: c, from: 0, toIndexRange: c.input.endIndex - 1 ..< c.input.endIndex, needTypoCorrection: false) let result = dicdataStore.lookupDicdata(composingText: c, inputRange: (0, c.input.endIndex - 1 ..< c.input.endIndex), needTypoCorrection: false)
XCTAssertTrue(result.contains(where: {$0.data.word == "テスト単語"})) XCTAssertTrue(result.contains(where: {$0.data.word == "テスト単語"}))
} }
@ -263,7 +263,7 @@ final class DicdataStoreTests: XCTestCase {
do { do {
var c = ComposingText() var c = ComposingText()
c.insertAtCursorPosition("ドウテキジショ", inputStyle: .direct) c.insertAtCursorPosition("ドウテキジショ", inputStyle: .direct)
let result = dicdataStore.getLOUDSDataInRange(inputData: c, from: 0, toIndexRange: c.input.endIndex - 1 ..< c.input.endIndex, needTypoCorrection: false) let result = dicdataStore.lookupDicdata(composingText: c, inputRange: (0, c.input.endIndex - 1 ..< c.input.endIndex), needTypoCorrection: false)
XCTAssertTrue(result.contains(where: {$0.data.word == "動的辞書"})) XCTAssertTrue(result.contains(where: {$0.data.word == "動的辞書"}))
} }
@ -288,7 +288,7 @@ final class DicdataStoreTests: XCTestCase {
do { do {
var c = ComposingText() var c = ComposingText()
sequentialInput(&c, sequence: "tesutowaーdo", inputStyle: .roman2kana) sequentialInput(&c, sequence: "tesutowaーdo", inputStyle: .roman2kana)
let result = dicdataStore.getLOUDSDataInRange(inputData: c, from: 0, toIndexRange: c.input.endIndex - 1 ..< c.input.endIndex, needTypoCorrection: false) let result = dicdataStore.lookupDicdata(composingText: c, inputRange: (0, c.input.endIndex - 1 ..< c.input.endIndex), needTypoCorrection: false)
XCTAssertTrue(result.contains(where: {$0.data.word == "テストワード"})) XCTAssertTrue(result.contains(where: {$0.data.word == "テストワード"}))
XCTAssertEqual(result.first(where: {$0.data.word == "テストワード"})?.range, .input(from: 0, to: 11)) XCTAssertEqual(result.first(where: {$0.data.word == "テストワード"})?.range, .input(from: 0, to: 11))
} }
@ -297,7 +297,7 @@ final class DicdataStoreTests: XCTestCase {
do { do {
var c = ComposingText() var c = ComposingText()
c.insertAtCursorPosition("トクシュヨミ", inputStyle: .direct) c.insertAtCursorPosition("トクシュヨミ", inputStyle: .direct)
let result = dicdataStore.getLOUDSDataInRange(inputData: c, from: 0, toIndexRange: c.input.endIndex - 1 ..< c.input.endIndex, needTypoCorrection: false) let result = dicdataStore.lookupDicdata(composingText: c, inputRange: (0, c.input.endIndex - 1 ..< c.input.endIndex), needTypoCorrection: false)
let dynamicUserDictResult = result.first(where: {$0.data.word == "特殊読み"}) let dynamicUserDictResult = result.first(where: {$0.data.word == "特殊読み"})
XCTAssertNotNil(dynamicUserDictResult) XCTAssertNotNil(dynamicUserDictResult)
XCTAssertEqual(dynamicUserDictResult?.data.metadata, .isFromUserDictionary) XCTAssertEqual(dynamicUserDictResult?.data.metadata, .isFromUserDictionary)