LMs // Make LMAssociates and LMReplacements parseless.
Co-Authored-By: ix4n33 <16833681+isaacxen@users.noreply.github.com>
This commit is contained in:
parent
6c66fd26c0
commit
556b0a61ff
|
@ -1,6 +1,5 @@
|
||||||
// Copyright (c) 2021 and onwards The vChewing Project (MIT-NTL License).
|
// Copyright (c) 2021 and onwards The vChewing Project (MIT-NTL License).
|
||||||
// Refactored from the ObjCpp-version of this class by:
|
// StringView Ranges extension by (c) 2022 and onwards Isaac Xen (MIT License).
|
||||||
// (c) 2011 and onwards The OpenVanilla Project (MIT License).
|
|
||||||
/*
|
/*
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||||
this software and associated documentation files (the "Software"), to deal in
|
this software and associated documentation files (the "Software"), to deal in
|
||||||
|
@ -28,18 +27,19 @@ import Foundation
|
||||||
|
|
||||||
extension vChewing {
|
extension vChewing {
|
||||||
@frozen public struct LMAssociates {
|
@frozen public struct LMAssociates {
|
||||||
var keyValueMap: [String: [Megrez.KeyValuePair]] = [:]
|
var rangeMap: [String: [Range<String.Index>]] = [:]
|
||||||
|
var strData: String = ""
|
||||||
|
|
||||||
public var count: Int {
|
public var count: Int {
|
||||||
keyValueMap.count
|
rangeMap.count
|
||||||
}
|
}
|
||||||
|
|
||||||
public init() {
|
public init() {
|
||||||
keyValueMap = [:]
|
rangeMap = [:]
|
||||||
}
|
}
|
||||||
|
|
||||||
public func isLoaded() -> Bool {
|
public func isLoaded() -> Bool {
|
||||||
!keyValueMap.isEmpty
|
!rangeMap.isEmpty
|
||||||
}
|
}
|
||||||
|
|
||||||
@discardableResult public mutating func open(_ path: String) -> Bool {
|
@discardableResult public mutating func open(_ path: String) -> Bool {
|
||||||
|
@ -50,53 +50,40 @@ extension vChewing {
|
||||||
LMConsolidator.fixEOF(path: path)
|
LMConsolidator.fixEOF(path: path)
|
||||||
LMConsolidator.consolidate(path: path, pragma: true)
|
LMConsolidator.consolidate(path: path, pragma: true)
|
||||||
|
|
||||||
var arrData: [String] = []
|
|
||||||
|
|
||||||
do {
|
do {
|
||||||
arrData = try String(contentsOfFile: path, encoding: .utf8).components(separatedBy: "\n")
|
strData = try String(contentsOfFile: path, encoding: .utf8).replacingOccurrences(of: "\t", with: " ")
|
||||||
|
strData.ranges(splitBy: "\n").forEach {
|
||||||
|
let neta = strData[$0].components(separatedBy: " ")
|
||||||
|
if neta.count >= 2 {
|
||||||
|
let theKey = neta[0]
|
||||||
|
if !neta[0].isEmpty, !neta[1].isEmpty, theKey.first != "#" {
|
||||||
|
let theValue = $0
|
||||||
|
rangeMap[theKey, default: []].append(theValue)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
} catch {
|
} catch {
|
||||||
IME.prtDebugIntel("\(error)")
|
IME.prtDebugIntel("\(error)")
|
||||||
IME.prtDebugIntel("↑ Exception happened when reading data at: \(path).")
|
IME.prtDebugIntel("↑ Exception happened when reading data at: \(path).")
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
for (lineID, lineContent) in arrData.enumerated() {
|
|
||||||
if !lineContent.hasPrefix("#") {
|
|
||||||
let lineContent = lineContent.replacingOccurrences(of: "\t", with: " ")
|
|
||||||
if lineContent.components(separatedBy: " ").count < 2 {
|
|
||||||
if lineContent != "", lineContent != " " {
|
|
||||||
IME.prtDebugIntel("Line #\(lineID + 1) Wrecked: \(lineContent)")
|
|
||||||
}
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
var currentKV = Megrez.KeyValuePair()
|
|
||||||
for (unitID, unitContent) in lineContent.components(separatedBy: " ").enumerated() {
|
|
||||||
switch unitID {
|
|
||||||
case 0:
|
|
||||||
currentKV.key = unitContent
|
|
||||||
case 1:
|
|
||||||
currentKV.value = unitContent
|
|
||||||
default: break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
keyValueMap[currentKV.key, default: []].append(currentKV)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
public mutating func close() {
|
public mutating func close() {
|
||||||
if isLoaded() {
|
if isLoaded() {
|
||||||
keyValueMap.removeAll()
|
rangeMap.removeAll()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public func dump() {
|
public func dump() {
|
||||||
var strDump = ""
|
var strDump = ""
|
||||||
for entry in keyValueMap {
|
for entry in rangeMap {
|
||||||
let rows: [Megrez.KeyValuePair] = entry.value
|
let netaRanges: [Range<String.Index>] = entry.value
|
||||||
for row in rows {
|
for netaRange in netaRanges {
|
||||||
let addline = row.key + " " + row.value + "\n"
|
let neta = strData[netaRange]
|
||||||
|
let addline = neta + "\n"
|
||||||
strDump += addline
|
strDump += addline
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -104,17 +91,33 @@ extension vChewing {
|
||||||
}
|
}
|
||||||
|
|
||||||
public func valuesFor(key: String) -> [String]? {
|
public func valuesFor(key: String) -> [String]? {
|
||||||
var v: [String] = []
|
var pairs: [String] = []
|
||||||
if let matched = keyValueMap[key] {
|
if let arrRangeRecords: [Range<String.Index>] = rangeMap[key] {
|
||||||
for entry in matched as [Megrez.KeyValuePair] {
|
for netaRange in arrRangeRecords {
|
||||||
v.append(entry.value)
|
let neta = strData[netaRange].components(separatedBy: " ")
|
||||||
|
let theValue: String = neta[1]
|
||||||
|
pairs.append(theValue)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return v
|
return pairs
|
||||||
}
|
}
|
||||||
|
|
||||||
public func hasValuesFor(key: String) -> Bool {
|
public func hasValuesFor(key: String) -> Bool {
|
||||||
keyValueMap[key] != nil
|
rangeMap[key] != nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// MARK: - StringView Ranges Extension (by Isaac Xen)
|
||||||
|
|
||||||
|
extension String {
|
||||||
|
fileprivate func ranges(splitBy separator: Element) -> [Range<String.Index>] {
|
||||||
|
var startIndex = startIndex
|
||||||
|
return split(separator: separator).reduce(into: []) { ranges, substring in
|
||||||
|
_ = range(of: substring, range: startIndex..<endIndex).map { range in
|
||||||
|
ranges.append(range)
|
||||||
|
startIndex = range.upperBound
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
// Copyright (c) 2021 and onwards The vChewing Project (MIT-NTL License).
|
// Copyright (c) 2021 and onwards The vChewing Project (MIT-NTL License).
|
||||||
// Refactored from the ObjCpp-version of this class by:
|
// StringView Ranges extension by (c) 2022 and onwards Isaac Xen (MIT License).
|
||||||
// (c) 2011 and onwards The OpenVanilla Project (MIT License).
|
|
||||||
/*
|
/*
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||||
this software and associated documentation files (the "Software"), to deal in
|
this software and associated documentation files (the "Software"), to deal in
|
||||||
|
@ -28,18 +27,19 @@ import Foundation
|
||||||
|
|
||||||
extension vChewing {
|
extension vChewing {
|
||||||
@frozen public struct LMReplacments {
|
@frozen public struct LMReplacments {
|
||||||
var keyValueMap: [String: String] = [:]
|
var rangeMap: [String: Range<String.Index>] = [:]
|
||||||
|
var strData: String = ""
|
||||||
|
|
||||||
public var count: Int {
|
public var count: Int {
|
||||||
keyValueMap.count
|
rangeMap.count
|
||||||
}
|
}
|
||||||
|
|
||||||
public init() {
|
public init() {
|
||||||
keyValueMap = [:]
|
rangeMap = [:]
|
||||||
}
|
}
|
||||||
|
|
||||||
public func isLoaded() -> Bool {
|
public func isLoaded() -> Bool {
|
||||||
!keyValueMap.isEmpty
|
!rangeMap.isEmpty
|
||||||
}
|
}
|
||||||
|
|
||||||
@discardableResult public mutating func open(_ path: String) -> Bool {
|
@discardableResult public mutating func open(_ path: String) -> Bool {
|
||||||
|
@ -50,58 +50,69 @@ extension vChewing {
|
||||||
LMConsolidator.fixEOF(path: path)
|
LMConsolidator.fixEOF(path: path)
|
||||||
LMConsolidator.consolidate(path: path, pragma: true)
|
LMConsolidator.consolidate(path: path, pragma: true)
|
||||||
|
|
||||||
var arrData: [String] = []
|
|
||||||
|
|
||||||
do {
|
do {
|
||||||
arrData = try String(contentsOfFile: path, encoding: .utf8).components(separatedBy: "\n")
|
strData = try String(contentsOfFile: path, encoding: .utf8).replacingOccurrences(of: "\t", with: " ")
|
||||||
|
strData.ranges(splitBy: "\n").forEach {
|
||||||
|
let neta = strData[$0].components(separatedBy: " ")
|
||||||
|
if neta.count >= 2 {
|
||||||
|
let theKey = neta[0]
|
||||||
|
if !neta[0].isEmpty, !neta[1].isEmpty, theKey.first != "#" {
|
||||||
|
let theValue = $0
|
||||||
|
rangeMap[theKey] = theValue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
} catch {
|
} catch {
|
||||||
IME.prtDebugIntel("\(error)")
|
IME.prtDebugIntel("\(error)")
|
||||||
IME.prtDebugIntel("↑ Exception happened when reading data at: \(path).")
|
IME.prtDebugIntel("↑ Exception happened when reading data at: \(path).")
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
for (lineID, lineContent) in arrData.enumerated() {
|
|
||||||
if !lineContent.hasPrefix("#") {
|
|
||||||
let lineContent = lineContent.replacingOccurrences(of: "\t", with: " ")
|
|
||||||
if lineContent.components(separatedBy: " ").count < 2 {
|
|
||||||
if lineContent != "", lineContent != " " {
|
|
||||||
IME.prtDebugIntel("Line #\(lineID + 1) Wrecked: \(lineContent)")
|
|
||||||
}
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
var currentKV = Megrez.KeyValuePair()
|
|
||||||
for (unitID, unitContent) in lineContent.components(separatedBy: " ").enumerated() {
|
|
||||||
switch unitID {
|
|
||||||
case 0:
|
|
||||||
currentKV.key = unitContent
|
|
||||||
case 1:
|
|
||||||
currentKV.value = unitContent
|
|
||||||
default: break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
keyValueMap[currentKV.key] = currentKV.value
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
public mutating func close() {
|
public mutating func close() {
|
||||||
if isLoaded() {
|
if isLoaded() {
|
||||||
keyValueMap.removeAll()
|
rangeMap.removeAll()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public func dump() {
|
public func dump() {
|
||||||
var strDump = ""
|
var strDump = ""
|
||||||
for entry in keyValueMap {
|
for entry in rangeMap {
|
||||||
strDump += entry.key + " " + entry.value + "\n"
|
strDump += strData[entry.value] + "\n"
|
||||||
}
|
}
|
||||||
IME.prtDebugIntel(strDump)
|
IME.prtDebugIntel(strDump)
|
||||||
}
|
}
|
||||||
|
|
||||||
public func valuesFor(key: String) -> String {
|
public func valuesFor(key: String) -> String {
|
||||||
keyValueMap[key] ?? ""
|
guard let range = rangeMap[key] else {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
let arrNeta = strData[range].components(separatedBy: " ")
|
||||||
|
guard arrNeta.count >= 2 else {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
return String(arrNeta[1])
|
||||||
|
}
|
||||||
|
|
||||||
|
public func hasValuesFor(key: String) -> Bool {
|
||||||
|
rangeMap[key] != nil
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// MARK: - StringView Ranges Extension (by Isaac Xen)
|
||||||
|
|
||||||
|
extension String {
|
||||||
|
fileprivate func ranges(splitBy separator: Element) -> [Range<String.Index>] {
|
||||||
|
var startIndex = startIndex
|
||||||
|
return split(separator: separator).reduce(into: []) { ranges, substring in
|
||||||
|
_ = range(of: substring, range: startIndex..<endIndex).map { range in
|
||||||
|
ranges.append(range)
|
||||||
|
startIndex = range.upperBound
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue