Skip to content

Commit

Permalink
modify: Lingoes pattern parser
Browse files Browse the repository at this point in the history
Convert raw string into specific structural object
  • Loading branch information
tinyAdapter committed Nov 19, 2019
1 parent ca80bb2 commit 1aaccac
Show file tree
Hide file tree
Showing 6 changed files with 390 additions and 23 deletions.
2 changes: 2 additions & 0 deletions package.json
Expand Up @@ -71,6 +71,7 @@
"vuetify-dialog": "^1.0.0-alpha.5",
"vuex": "^3.0.1",
"wanakana": "^4.0.2",
"xml2js": "^0.4.22",
"xterm": "^4.2.0-vscode1",
"xterm-addon-fit": "^0.3.0"
},
Expand All @@ -85,6 +86,7 @@
"@types/request-promise-native": "^1.0.15",
"@types/sqlite3": "^3.1.5",
"@types/vue-color": "^2.4.1",
"@types/xml2js": "^0.4.5",
"ajv": "^6.5.0",
"babel-core": "^6.26.3",
"babel-loader": "^7.1.4",
Expand Down
118 changes: 112 additions & 6 deletions src/main/translate/LingoesDict.ts
@@ -1,7 +1,111 @@
import * as sqlite3 from 'sqlite3'
import * as xml2js from 'xml2js'
const debug = require('debug')('yuki:dict:lingoes')

export default class LingoesDict {

public static contentToObject (
content: string,
callback: (pattern?: yuki.LingoesPattern) => void
) {
xml2js.parseString(content, (err, result: any) => {
if (err) callback()
const refinedResult: yuki.LingoesPattern = {}
let parseResult: any = { ...result }
if (!parseResult.C) {
callback()
return
}
parseResult = parseResult.C
if (!parseResult.F) {
callback()
return
}
parseResult = parseResult.F
if (!parseResult[0]) {
callback()
return
}
parseResult = parseResult[0]
if (parseResult.H) {// parse kana
let kanaResult = parseResult.H
if (kanaResult[0]) {
kanaResult = kanaResult[0]
if (kanaResult.M) {
kanaResult = kanaResult.M
}
refinedResult.kana = kanaResult
}
}

if (!parseResult.I) {
callback(refinedResult)
return
}
parseResult = parseResult.I
if (!parseResult[0]) {
callback(refinedResult)
return
}
parseResult = parseResult[0]
if (!parseResult.N) {
callback(refinedResult)
return
}
parseResult = parseResult.N
if (parseResult[0]) {// parse parts of speech and explanations
refinedResult.definitions = []
for (let definitionResult of parseResult) {
const oneDefinition: any = {}
if (!definitionResult.P) {
oneDefinition.partOfSpeech = undefined
} else {
oneDefinition.partOfSpeech = definitionResult.P[0].U[0]
}
if (!definitionResult.Q) {
oneDefinition.explanations = undefined
} else {
oneDefinition.explanations = []
definitionResult = definitionResult.Q
let oneExplanation = {
content: '',
example: {
sentence: '',
content: ''
}
}
for (const iStr in definitionResult) {
const i = Number.parseInt(iStr, 10)
if (typeof definitionResult[i] === 'string') {
// appendix of the last explanation
oneExplanation.content += definitionResult[i]
} else if (typeof definitionResult[i] === 'object') {
// end of the last explanation, with potential example
oneExplanation.content += definitionResult[i]._
oneExplanation.example.sentence = definitionResult[i].T[0].W[0]
oneExplanation.example.content = definitionResult[i].T[0].X[0]
oneDefinition.explanations.push(oneExplanation)
oneExplanation = {
content: '',
example: {
sentence: '',
content: ''
}
}
} else {
// Error, stop parsing
break
}
}
}
refinedResult.definitions.push(oneDefinition)
}
}

callback(refinedResult)
})
}

private config: yuki.Config.LibraryItem
private db: sqlite3.Database | undefined

Expand All @@ -17,8 +121,6 @@ export default class LingoesDict {
if (!this.db) return

this.db.all('SELECT content from entry where word = ?', word, (err, rows) => {
debug('raw rows from sqlite: %s -> %o', word, rows)

if (err) {
callback({ found: false })
return
Expand All @@ -28,10 +130,14 @@ export default class LingoesDict {
return
}

callback({
found: true,
word,
content: rows[0].content
LingoesDict.contentToObject(rows[0].content, (pattern) => {
debug('raw content object from sqlite: %s -> %o', word, pattern)

callback({
found: true,
word,
content: pattern
})
})
})
}
Expand Down
16 changes: 15 additions & 1 deletion src/types/common.d.ts
Expand Up @@ -14,11 +14,25 @@ declare namespace yuki {
export interface DictResult {
found?: boolean
word?: string
content?: string
content?: LingoesPattern
}

export interface DictOptions {
dict: string
word: string
}

export interface LingoesPattern {
kana?: Array<String>
definitions?: Array<{
partOfSpeech: string,
explanations: Array<{
content: string,
example: {
sentence: string,
content: string
}
}>
}>
}
}
37 changes: 23 additions & 14 deletions test/unit/specs/main/LingoesDict.spec.ts
Expand Up @@ -6,24 +6,35 @@ import * as path from 'path'
import LingoesDict from '../../../../src/main/translate/LingoesDict'

describe('LingoesDict', () => {
it('returns correct result if found', (done) => {
it('returns correct pattern if found', (done) => {
const lingoes = new LingoesDict({
enable: true,
path: path.resolve(__dirname, '../../../../../libraries/dict/lingoes/njcd.db')
})

lingoes.find('かわいい', (result) => {
// tslint:disable-next-line: no-console
console.log(result)
lingoes.find('1', (result) => {
try {
expect(result).to.deep.equal({
found: true,
word: 'かわいい',
content: '<C><F><H /><I><N><P><U>形</U></P><Q>可愛い</Q><Q>可爱。' +
'<T><W>かわいい女の子</W><X>可爱的小女孩儿。</X></T></Q><Q>小' +
'巧玲珑。<T><h><W>かわいい子には旅をさせよ</W><X>不可娇生惯养。<' +
'/X></h></T></Q><Q>かわいいさ,かわいいげ</Q></N></I></F></C>'
})
expect(result).to.deep.equal(JSON.parse('{"found":true,"word":"1","content":{"kana":["' +
'イチ·イツ","ひと·ひとつ·ひ"],"definitions":[{"partOfSpeech":"(H10","explanation' +
's":[{"content":"一,第一。","example":{"sentence":"一月(いちがつ)·一番(いちばん)·一' +
'姫二太郎(いちひめにたろう)。","content":""}},{"content":"一个。","example":{"sente' +
'nce":"一々(いちいち)·一因(いちいん)·一個(いっこ)·一民間会社(いちみんかんがいしゃ)。","con' +
'tent":""}},{"content":"一次。","example":{"sentence":"一敗(いっぱい)·一面識(いちめ' +
'んしき)。","content":""}},{"content":"最优秀,最好,第一。","example":{"sentence":"' +
'一流(いちりゅう)·一位(いちい)。","content":""}},{"content":"表示全体,都。","example"' +
':{"sentence":"一切(いっさい)·一族(いちぞく)·一座(いちざ)。","content":""}},{"content"' +
':"某,另外的,别的。","example":{"sentence":"一夜(いちや)·一説(いっせつ)·一書(いっしょ)。' +
'","content":""}},{"content":"普通的。","example":{"sentence":"一介(いっかい)·一教' +
'師(いちきょうし)·一読者(いちどくしゃ)。","content":""}},{"content":"相同,同样(合为一体)' +
'。","example":{"sentence":"一概(いちがい)·一咽(いちよう)·同一(どういつ)·画一(かくいつ)。' +
'","content":""}},{"content":"专一,一心。","example":{"sentence":"一念(いちねん)·' +
'一途(いちず)·純一(じゅんいつ)·一意專心(いちいせんしん)。","content":""}},{"content":")仅,' +
'只,一点儿。","example":{"sentence":"一寸(ちょっと·いっすん)·一瞬(いっしゅん)·一言(いちご' +
'ん)。","content":""}}]},{"partOfSpeech":"(H11","explanations":[{"content":")或。"' +
',"example":{"sentence":"一喜一憂(いっきいちゆう)·一得一失(いっとくいっしつ)。","content":' +
'""}}]},{"partOfSpeech":"(H12","explanations":[{"content":")用于强调或调整语气(带有不' +
'容忽视之意)。","example":{"sentence":"一見識(いっけんしき·いちけんしき)·一考察(いちこうさ' +
'つ)。","content":""}}]}]}}'))
lingoes.close()
done()
} catch (e) {
Expand All @@ -40,8 +51,6 @@ describe('LingoesDict', () => {
})

lingoes.find('キミ', (result) => {
// tslint:disable-next-line: no-console
console.log(result)
try {
expect(result).to.deep.equal({
found: false
Expand Down

0 comments on commit 1aaccac

Please sign in to comment.