11import { 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