From 14e4b6b1c364c94fbc95f9ba5af5b569cc473d1b Mon Sep 17 00:00:00 2001 From: Kai Date: Fri, 3 May 2024 14:59:18 +0900 Subject: [PATCH] =?UTF-8?q?refactor:=20TuningTranscription=E3=81=AE?= =?UTF-8?q?=E3=82=B3=E3=83=BC=E3=83=89=E9=87=8F=E3=82=92=E5=89=8A=E6=B8=9B?= =?UTF-8?q?=20(#2005)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * refactor: flatArrayを組み込みAPIで作ることでコード量を削減 * refactor: 差分アルゴリズムを変更して、配列の破壊的変更を行わないようにする * refactor: 要らなくなったものを削除 * refactor: 変数名や関数名を改善する * refactor: コメントを追加 * fix: typo修正 * refactor: 型アサーションの削除と、関数名を改善 * コメントをちょっとだけ変更 --------- Co-authored-by: Hiroshiba --- package-lock.json | 25 +++++------ package.json | 2 +- src/store/utility.ts | 103 +++++++++++-------------------------------- 3 files changed, 37 insertions(+), 93 deletions(-) diff --git a/package-lock.json b/package-lock.json index 9e9d91a0b3..3afa2483a5 100644 --- a/package-lock.json +++ b/package-lock.json @@ -17,10 +17,10 @@ "clone-deep": "4.0.1", "core-js": "3.12.1", "dayjs": "1.10.7", - "diff": "5.1.0", "electron-log": "5.0.0", "electron-window-state": "5.0.3", "encoding-japanese": "1.0.30", + "fast-array-diff": "1.1.0", "glob": "8.0.3", "hotkeys-js": "3.13.6", "immer": "9.0.21", @@ -6299,14 +6299,6 @@ "dev": true, "optional": true }, - "node_modules/diff": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/diff/-/diff-5.1.0.tgz", - "integrity": "sha512-D+mk+qE8VC/PAUrlAU34N+VfXev0ghe5ywmpqrawphmVZc1bEfn56uo9qpyGp1p4xpzOHkSW4ztBd6L7Xx4ACw==", - "engines": { - "node": ">=0.3.1" - } - }, "node_modules/diff-sequences": { "version": "29.6.3", "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-29.6.3.tgz", @@ -7570,6 +7562,11 @@ ], "optional": true }, + "node_modules/fast-array-diff": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/fast-array-diff/-/fast-array-diff-1.1.0.tgz", + "integrity": "sha512-muSPyZa/yHCoDQhah9th57AmLENB1nekbrUoLAqOpQXdl1Kw8VbH24Syl5XLscaQJlx7KRU95bfTDPvVB5BJvw==" + }, "node_modules/fast-deep-equal": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", @@ -18837,11 +18834,6 @@ "dev": true, "optional": true }, - "diff": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/diff/-/diff-5.1.0.tgz", - "integrity": "sha512-D+mk+qE8VC/PAUrlAU34N+VfXev0ghe5ywmpqrawphmVZc1bEfn56uo9qpyGp1p4xpzOHkSW4ztBd6L7Xx4ACw==" - }, "diff-sequences": { "version": "29.6.3", "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-29.6.3.tgz", @@ -19822,6 +19814,11 @@ "integrity": "sha512-Wrk35e8ydCKDj/ArClo1VrPVmN8zph5V4AtHwIuHhvMXsKf73UT3BOD+azBIW+3wOJ4FhEH7zyaJCFvChjYvMA==", "optional": true }, + "fast-array-diff": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/fast-array-diff/-/fast-array-diff-1.1.0.tgz", + "integrity": "sha512-muSPyZa/yHCoDQhah9th57AmLENB1nekbrUoLAqOpQXdl1Kw8VbH24Syl5XLscaQJlx7KRU95bfTDPvVB5BJvw==" + }, "fast-deep-equal": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", diff --git a/package.json b/package.json index 1477847127..c3f76082b0 100644 --- a/package.json +++ b/package.json @@ -44,10 +44,10 @@ "clone-deep": "4.0.1", "core-js": "3.12.1", "dayjs": "1.10.7", - "diff": "5.1.0", "electron-log": "5.0.0", "electron-window-state": "5.0.3", "encoding-japanese": "1.0.30", + "fast-array-diff": "1.1.0", "glob": "8.0.3", "hotkeys-js": "3.13.6", "immer": "9.0.21", diff --git a/src/store/utility.ts b/src/store/utility.ts index 6689f23d19..a5379bf5c0 100644 --- a/src/store/utility.ts +++ b/src/store/utility.ts @@ -1,6 +1,6 @@ import path from "path"; import { Platform } from "quasar"; -import { diffArrays } from "diff"; +import * as diff from "fast-array-diff"; import { CharacterInfo, StyleInfo, @@ -216,8 +216,7 @@ function skipMemoText(targettext: string): string { } /** - * 2つのアクセント句配列を比べて同じだと思われるモーラの調整結果を転写し - * 変更前のアクセント句の調整結果を変更後のアクセント句に保持する。 + * 調整したモーラのパラメーターがリセットされるのを防ぐ * * <例> * 「こんにちは」 -> 「こんばんは」と変更した場合、[]に囲まれる部分で変更前のモーラが転写される。 @@ -231,81 +230,35 @@ export class TuningTranscription { this.afterAccent = JSON.parse(JSON.stringify(afterAccent)); } - private createFlatArray( - collection: T[], - key: K, - ): T[K] extends (infer U)[] ? U[] : T[K][] { - const result = []; - for (const element of collection) { - const value = element[key]; - if (Array.isArray(value)) { - result.push(...value); - } else { - result.push(value); - } - } - return result as T[K] extends (infer U)[] ? U[] : T[K][]; - } - /** - * 変更前の配列を操作してpatchMora配列を作る。 - * - * <例> (Uはundefined) - * 変更前 [ ズ, ン, ダ, モ, ン, ナ, ノ, ダ ] - * 変更後 [ ボ, ク, ズ, ン, ダ, ナ, ノ, デ, ス ] - * - * 再利用される文字列とundefinedで構成されたデータを作る。 - * [ U, U, ズ, ン, ダ, ナ, ノ, U, U ] - * - * 実際には"ズ"などの文字列部分は{text: "ズ"...}のようなデータ構造になっている。 - * [ U, U, {text: "ズ"...}, {text: "ン"...}, {text: "ダ"...}, {text: "ナ"...}, {text: "ノ"...}, U, U ] + * 変更前と変更後のAccentPhraseに存在するモーラの差分を取得し + * 変更内容を適用したモーラの配列を返す */ - private createDiffPatch() { + private createTranscriptionSource() { const before = structuredClone(this.beforeAccent); const after = structuredClone(this.afterAccent); + const beforeFlatArray = before.flatMap((accent) => accent.moras); + const afterFlatArray = after.flatMap((accent) => accent.moras); - const beforeFlatArray = this.createFlatArray(before, "moras"); - const afterFlatArray = this.createFlatArray(after, "moras"); - const diffed = diffArrays( - this.createFlatArray(beforeFlatArray, "text"), - this.createFlatArray(afterFlatArray, "text"), + // beforeFlatArrayとafterFlatArrayの特定の要素が一致するかどうかを判定する関数 + const matchRequirements = (beforeMora: Mora, afterMora: Mora) => + beforeMora?.text === afterMora?.text; + + const morasDiff = diff.getPatch( + beforeFlatArray, + afterFlatArray, + matchRequirements, ); - // FIXME: beforeFlatArrayを破壊的に変更しなくても良いようにしてasを不要にする - let currentTextIndex = 0; - for (const diff of diffed) { - if (diff.removed) { - beforeFlatArray.splice(currentTextIndex, diff.count); - } else if (diff.added) { - diff.value.forEach(() => { - beforeFlatArray.splice( - currentTextIndex, - 0, - undefined as never as Mora, - ); - currentTextIndex++; - }); - } else { - currentTextIndex += diff.value.length; - } - } - return beforeFlatArray as (Mora | undefined)[]; + return diff.applyPatch(beforeFlatArray, morasDiff); } /** - * moraPatchとafterAccentを比較し、textが一致するモーラを転写する。 - * - * <例> (「||」は等号記号を表す) - * 「こんにちは」 -> 「こんばんは」 とテキストを変更した場合、以下の例のように比較する。 - * - * moraPatch = [ {text: "コ"...}, {text: "ン"...}, undefined , undefined , {text: "ハ"...} ] - * || || || - * after[...]["moras"] = [ {text: "コ"...}, {text: "ン"...}, {text: "バ"...}, {text: "ン"...}, {text: "ハ"...} ] - * - * あとは一致したモーラを転写するだけ。 - * + * transcriptionSourceのモーラ配列のうち、テキストが一致するものを変更後のAccentPhraseの各モーラに適用する */ - private mergeAccentPhrases(moraPatch: (Mora | undefined)[]): AccentPhrase[] { + private applyTranscriptionSource( + transcriptionSource: Mora[], + ): AccentPhrase[] { const after: AccentPhrase[] = structuredClone(this.afterAccent); let moraPatchIndex = 0; @@ -316,18 +269,12 @@ export class TuningTranscription { moraIndex < after[accentIndex]["moras"].length; moraIndex++ ) { - // undefinedのとき、何もせず次のモーラへ移動 - if (moraPatch[moraPatchIndex] == undefined) { - moraPatchIndex++; - continue; - } if ( after[accentIndex]["moras"][moraIndex].text === - moraPatch[moraPatchIndex]?.text + transcriptionSource[moraPatchIndex]?.text ) { - after[accentIndex]["moras"][moraIndex] = moraPatch[ - moraPatchIndex - ] as Mora; + after[accentIndex]["moras"][moraIndex] = + transcriptionSource[moraPatchIndex]; } moraPatchIndex++; } @@ -337,8 +284,8 @@ export class TuningTranscription { } transcribe() { - const moraPatch = this.createDiffPatch(); - return this.mergeAccentPhrases(moraPatch as never); + const transcriptionSource = this.createTranscriptionSource(); + return this.applyTranscriptionSource(transcriptionSource); } }