Skip to content

Commit 90c0c94

Browse files
committed
fi
1 parent 286c7ae commit 90c0c94

File tree

7 files changed

+249
-208
lines changed

7 files changed

+249
-208
lines changed

deno.jsonc

Lines changed: 0 additions & 54 deletions
This file was deleted.

deno.lock

Lines changed: 0 additions & 42 deletions
This file was deleted.

h2z_test.ts

Lines changed: 0 additions & 26 deletions
This file was deleted.

mod.ts

Lines changed: 88 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -1,63 +1,99 @@
11
import { createConversionTables } from "./table.ts";
22

3-
const convTable = createConversionTables();
4-
5-
export function z2h(str: string): string {
6-
if (str === null) return ""
7-
if (str === "") return ""
8-
let result = "";
9-
let isHankaku = false;
10-
11-
// 半角文字が含まれているかチェック
12-
for (let i = 0; i < str.length; i++) {
13-
const char = str[i];
14-
if (hankakuToZenkakuMap.has(char)) {
15-
isHankaku = true;
16-
break;
17-
}
18-
}
3+
const convTables = createConversionTables();
194

20-
for (const char of str) {
21-
if (isHankaku) {
22-
result += zenkakuToHankakuMap.get(char) || char; // 半角に変換
23-
} else {
24-
result += char; // そのまま
25-
}
5+
6+
export function h2z(str: string | null): string {
7+
if (str === null || str === "") {
8+
return "";
269
}
27-
return result;
28-
}
10+
// 文字列をUnicodeコードポイントの配列に変換 (サロゲートペア対応)
11+
const runes = Array.from(str);
12+
const runeLen = runes.length;
13+
const resultParts: string[] = [];
2914

15+
let i = 0;
16+
while (i < runeLen) {
17+
const char = runes[i];
18+
let consumedCombined = false; // 現在の文字が次の文字と結合されたかを示すフラグ
3019

31-
export function h2z(str: string): string {
32-
if (str === null) return "";
33-
if (str === "") return ""
34-
let result = "";
35-
let isZenkaku = false;
36-
37-
for (let i = 0; i < str.length; i++) {
38-
const char = str[i];
39-
// 全角文字が含まれているかチェック
40-
if (zenkakuToHankakuMap.has(char)) {
41-
isZenkaku = true;
42-
break;
43-
}
20+
// 次の文字が存在するか確認し、濁点・半濁点との結合を試みる
21+
if (i + 1 < runeLen) {
22+
const nextChar = runes[i + 1];
23+
24+
if (nextChar === '゙') {
25+
const zenkakuDakuten = convTables.KANA_H2Z_DAKUTEN_MAP[char];
26+
if (zenkakuDakuten !== undefined) {
27+
resultParts.push(zenkakuDakuten);
28+
i += 2; // 現在の文字と濁点の両方を消費
29+
consumedCombined = true;
30+
}
31+
} else if (nextChar === '゚') { // 半角半濁点 (U+FF9F)
32+
const zenkakuHandakuten = convTables.KANA_H2Z_MARU_MAP[char];
33+
if (zenkakuHandakuten !== undefined) {
34+
resultParts.push(zenkakuHandakuten);
35+
i += 2; // 現在の文字と半濁点の両方を消費
36+
consumedCombined = true;
37+
}
38+
}
39+
}
40+
41+
// 結合されなかった場合、通常の文字変換を試みる
42+
if (!consumedCombined) {
43+
const c1 = convTables.ASCII_H2Z_CHARS_MAP[char];
44+
const c2 = convTables.KANA_H2Z_CHARS_MAP[char];
45+
const c3 = convTables.DIGIT_H2Z_CHARS_MAP[char];
46+
47+
if (c1 !== undefined) resultParts.push(c1);
48+
else if (c2 !== undefined) resultParts.push(c2);
49+
else if (c3 !== undefined) resultParts.push(c3);
50+
else resultParts.push(char); // 変換対象外の文字はそのまま
51+
52+
i++;
53+
}
4454
}
55+
return resultParts.join("");
56+
}
4557

46-
for (let i = 0; i < str.length; i++) {
47-
const char = str[i];
48-
if (char === "゙" && i > 0 && KANA_TEN_MAP.has(str[i - 1])) {
49-
result = result.slice(0, -1) + KANA_TEN_MAP.get(str[i - 1]);
50-
continue;
51-
}
52-
if (char === "゚" && i > 0 && KANA_MARU_MAP.has(str[i - 1])) {
53-
result = result.slice(0, -1) + KANA_MARU_MAP.get(str[i - 1]);
54-
continue;
58+
export function z2h(str: string | null): string {
59+
if (str === null || str === "") {
60+
return "";
5561
}
56-
if (isZenkaku) {
57-
result += hankakuToZenkakuMap.get(char) || char; // 全角に変換
58-
} else {
59-
result += char; // そのまま
62+
63+
const runes = Array.from(str);
64+
const runeLen = runes.length;
65+
const resultParts: string[] = [];
66+
67+
let i = 0;
68+
while (i < runeLen) {
69+
const char = runes[i];
70+
let consumed = false;
71+
72+
// 全角カタカナの濁点・半濁点文字を分解する試み
73+
const decomposedDakuten = convTables.KANA_Z2H_DAKUTEN_MAP[char];
74+
if (decomposedDakuten !== undefined) {
75+
resultParts.push(decomposedDakuten);
76+
consumed = true;
77+
} else {
78+
const decomposedHandakuten = convTables.KANA_Z2H_MARU_MAP[char];
79+
if (decomposedHandakuten !== undefined) {
80+
resultParts.push(decomposedHandakuten);
81+
consumed = true;
82+
}
83+
}
84+
85+
if (!consumed) {
86+
// 通常の全角→半角変換
87+
const c1 = convTables.ASCII_Z2H_CHARS_MAP[char];
88+
const c2 = convTables.KANA_Z2H_CHARS_MAP[char];
89+
const c3 = convTables.DIGIT_Z2H_CHARS_MAP[char];
90+
91+
if (c1 !== undefined) resultParts.push(c1);
92+
else if (c2 !== undefined) resultParts.push(c2);
93+
else if (c3 !== undefined) resultParts.push(c3);
94+
else resultParts.push(char); // 変換対象外の文字はそのまま
95+
}
96+
i++;
6097
}
61-
}
62-
return result;
98+
return resultParts.join("");
6399
}

0 commit comments

Comments
 (0)