PageSourceSearch

https://bris.go.kr/resources/js/portal/common/hangul.js

js bris.go.kr collected 2026-10-02 14:51:13 UTC 26,193 bytes, 595 lines download raw bytes

1/**
2 * Hangul.js
3 * https://github.com/e-/Hangul.js
4 *
5 * Copyright 2017, Jaemin Jo
6 * under the MIT license.
7 */
8
9(function () {
10    'use strict';
11        /* Disassembled 초성(onset) */
12    var CHO = [
13            'ㄱ', 'ㄲ', 'ㄴ', 'ㄷ', 'ㄸ',
14            'ㄹ', 'ㅁ', 'ㅂ', 'ㅃ', 'ㅅ', 'ㅆ',
15            'ㅇ', 'ㅈ', 'ㅉ', 'ㅊ', 'ㅋ', 'ㅌ',
16            'ㅍ', 'ㅎ'
17        ],
18        /* Disassembled 중성(nucleus) */
19        JUNG = [
20            'ㅏ', 'ㅐ', 'ㅑ', 'ㅒ', 'ㅓ',
21            'ㅔ', 'ㅕ', 'ㅖ', 'ㅗ', ['ㅗ', 'ㅏ'], ['ㅗ', 'ㅐ'],
22            ['ㅗ', 'ㅣ'], 'ㅛ', 'ㅜ', ['ㅜ', 'ㅓ'], ['ㅜ', 'ㅔ'], ['ㅜ', 'ㅣ'],
23            'ㅠ', 'ㅡ', ['ㅡ', 'ㅣ'], 'ㅣ'
24        ],
25        /* Desassembled 종성(coda) */
26        JONG = [
27            '', 'ㄱ', 'ㄲ', ['ㄱ', 'ㅅ'], 'ㄴ', ['ㄴ', 'ㅈ'], ['ㄴ', 'ㅎ'], 'ㄷ', 'ㄹ',
28            ['ㄹ', 'ㄱ'], ['ㄹ', 'ㅁ'], ['ㄹ', 'ㅂ'], ['ㄹ', 'ㅅ'], ['ㄹ', 'ㅌ'], ['ㄹ', 'ㅍ'], ['ㄹ', 'ㅎ'], 'ㅁ',
29            'ㅂ', ['ㅂ', 'ㅅ'], 'ㅅ', 'ㅆ', 'ㅇ', 'ㅈ', 'ㅊ', 'ㅋ', 'ㅌ', 'ㅍ', 'ㅎ'
30        ],
31        /* 유니코드 한글 시작 위치 */
32        HANGUL_OFFSET = 0xAC00, 
33        /* 자음 */
34        CONSONANTS = [
35            'ㄱ', 'ㄲ', 'ㄳ', 'ㄴ', 'ㄵ', 'ㄶ', 'ㄷ', 'ㄸ',
36            'ㄹ', 'ㄺ', 'ㄻ', 'ㄼ', 'ㄽ', 'ㄾ', 'ㄿ', 'ㅀ',
37            'ㅁ', 'ㅂ', 'ㅃ', 'ㅄ', 'ㅅ', 'ㅆ', 'ㅇ', 'ㅈ',
38            'ㅉ', 'ㅊ', 'ㅋ', 'ㅌ', 'ㅍ', 'ㅎ'
39        ],
40        /* Assembled 초성 */
41        COMPLETE_CHO = [
42            'ㄱ', 'ㄲ', 'ㄴ', 'ㄷ', 'ㄸ',
43            'ㄹ', 'ㅁ', 'ㅂ', 'ㅃ', 'ㅅ', 'ㅆ',
44            'ㅇ', 'ㅈ', 'ㅉ', 'ㅊ', 'ㅋ', 'ㅌ', 'ㅍ', 'ㅎ'
45        ],
46        /* Assembled 중성 */
47        COMPLETE_JUNG = [
48            'ㅏ', 'ㅐ', 'ㅑ', 'ㅒ', 'ㅓ',
49            'ㅔ', 'ㅕ', 'ㅖ', 'ㅗ', 'ㅘ', 'ㅙ',
50            'ㅚ', 'ㅛ', 'ㅜ', 'ㅝ', 'ㅞ', 'ㅟ',
51            'ㅠ', 'ㅡ', 'ㅢ', 'ㅣ'
52        ],
53        /* Assembled 종성 */
54        COMPLETE_JONG = [
55            '', 'ㄱ', 'ㄲ', 'ㄳ', 'ㄴ', 'ㄵ', 'ㄶ', 'ㄷ', 'ㄹ',
56            'ㄺ', 'ㄻ', 'ㄼ', 'ㄽ', 'ㄾ', 'ㄿ', 'ㅀ', 'ㅁ',
57            'ㅂ', 'ㅄ', 'ㅅ', 'ㅆ', 'ㅇ', 'ㅈ', 'ㅊ', 'ㅋ', 'ㅌ', 'ㅍ', 'ㅎ'
58        ],
59        /* 복잡한 자음: [ 자음1, 자음2, 자음1+자음2 ] */
60        COMPLEX_CONSONANTS = [
61            ['ㄱ', 'ㅅ', 'ㄳ'],
62            ['ㄴ', 'ㅈ', 'ㄵ'],
63            ['ㄴ', 'ㅎ', 'ㄶ'],
64            ['ㄹ', 'ㄱ', 'ㄺ'],
65            ['ㄹ', 'ㅁ', 'ㄻ'],
66            ['ㄹ', 'ㅂ', 'ㄼ'],
67            ['ㄹ', 'ㅅ', 'ㄽ'],
68            ['ㄹ', 'ㅌ', 'ㄾ'],
69            ['ㄹ', 'ㅍ', 'ㄿ'],
70            ['ㄹ', 'ㅎ', 'ㅀ'],
71            ['ㅂ', 'ㅅ', 'ㅄ']
72        ],
73        /* 복잡한 모음: [모음1, 모음2, 모음1+모음2] */
74        COMPLEX_VOWELS = [
75            ['ㅗ', 'ㅏ', 'ㅘ'],
76            ['ㅗ', 'ㅐ', 'ㅙ'],
77            ['ㅗ', 'ㅣ', 'ㅚ'],
78            ['ㅜ', 'ㅓ', 'ㅝ'],
79            ['ㅜ', 'ㅔ', 'ㅞ'],
80            ['ㅜ', 'ㅣ', 'ㅟ'],
81            ['ㅡ', 'ㅣ', 'ㅢ']
82        ],
83        CONSONANTS_HASH,
84        CHO_HASH,
85        JUNG_HASH,
86        JONG_HASH,
87        COMPLEX_CONSONANTS_HASH,
88        COMPLEX_VOWELS_HASH
89        ;
90
91    function _makeHash(array) {
92        var length = array.length,
93            hash = { 0: 0 }
94            ;
95        for (var i = 0; i < length; i++) {
96            if (array[i])
97                hash[array[i].charCodeAt(0)] = i;
98        }
99        return hash;
100    }
101
102    CONSONANTS_HASH = _makeHash(CONSONANTS);
103    CHO_HASH = _makeHash(COMPLETE_CHO);
104    JUNG_HASH = _makeHash(COMPLETE_JUNG);
105    JONG_HASH = _makeHash(COMPLETE_JONG);
106
107    function _makeComplexHash(array) {
108        var length = array.length,
109            hash = {},
110            code1,
111            code2
112            ;
113        for (var i = 0; i < length; i++) {
114            code1 = array[i][0].charCodeAt(0);
115            code2 = array[i][1].charCodeAt(0);
116            if (typeof hash[code1] === 'undefined') {
117                hash[code1] = {};
118            }
119            hash[code1][code2] = array[i][2].charCodeAt(0);
120        }
121        return hash;
122    }
123
124    COMPLEX_CONSONANTS_HASH = _makeComplexHash(COMPLEX_CONSONANTS);
125    COMPLEX_VOWELS_HASH = _makeComplexHash(COMPLEX_VOWELS);
126
127    /* c 가 CONSONANTS의 멤버일 경우 true 반환 (c가 자음일 경우 true 반환) */ 
128    function _isConsonant(c) {
129        return typeof CONSONANTS_HASH[c] !== 'undefined';
130    }
131    /* c 가 COMPLETE_JUNG의 멤버일 경우 true 반환 (c 가 초성일 경우 true 반환) */
132    function _isCho(c) {
133        return typeof CHO_HASH[c] !== 'undefined';
134    }
135    /* c 가 COMPLETE_JUNG의 멤버일 경우 true 반환 (c 가 중성일 경우 true 반환) */
136    function _isJung(c) {
137        return typeof JUNG_HASH[c] !== 'undefined';
138    }
139    /* c 가 COMPLETE_JONG의 멤버일 경우 true 반환 (c 가 종성일 경우 true 반환) */
140    function _isJong(c) {
141        return typeof JONG_HASH[c] !== 'undefined';
142    }
143    /* c 가 한글일 경우 true 반환 */
144    function _isHangul(c /* code number */) {
145        return 0xAC00 <= c && c <= 0xd7a3;
146    }
147    /* a와 b가 중성으로서 결합할 수 있는 경우 COMPLEX_VOWELS_HASH[a][b] 값(결합한 종성의 유니코드 값) 반환 */
148    function _isJungJoinable(a, b) {
149        return (COMPLEX_VOWELS_HASH[a] && COMPLEX_VOWELS_HASH[a][b]) ? COMPLEX_VOWELS_HASH[a][b] : false;
150    }
151    /* a와 b가 종성으로서 결합할 수 있는 경우 COMPLEX_CONSONANTS_HASH[a][b] 값(결합한 종성의 유니코드 값) 반환 */
152    function _isJongJoinable(a, b) {
153        return COMPLEX_CONSONANTS_HASH[a] && COMPLEX_CONSONANTS_HASH[a][b] ? COMPLEX_CONSONANTS_HASH[a][b] : false;
154    }
155    
156    var disassemble = function (string, grouped) {
157        /* 입력값이 NULL일 경우 에러 발생 */
158        if (string === null) {
159            throw new Error('Arguments cannot be null');
160        }
161        /* 입력값이 'object' 타입인 경우 문자열로 병합 */
162        if (typeof string === 'object') {
163            string = string.join('');
164        }
165        
166        var result = [],
167            length = string.length,
168            cho,
169            jung,
170            jong,
171            code,
172            r
173            ;
174        /* 모든 문자에 대해 확인 */
175        for (var i = 0; i < length; i++) {
176            var temp = [];
177            
178            code = string.charCodeAt(i); //문자를 유니코드값으로 변환해 code에 저장
179            /* i번째 문자(code)가 완성된 한글인 경우 */
180            if (_isHangul(code)) {
181                code -= HANGUL_OFFSET;
182                jong = code % 28;
183                jung = (code - jong) / 28 % 21;
184                cho = parseInt((code - jong) / 28 / 21);
185                temp.push(CHO[cho]); // temp 배열에 초성 추가
186                /* 중성이 object형인 경우 (2 단일 모음의 조합인 경우) */
187                if (typeof JUNG[jung] === 'object') {
188                    temp = temp.concat(JUNG[jung]); // temp에 해당 중성의 모음들 추가
189                /* 중성이 단일 모음으로 이루어진 경우 */
190                } else {
191                    temp.push(JUNG[jung]); // temp에 해당 모음 추가
192                }
193                /* 종성이 있는 경우 */
194                if (jong > 0) {
195                    /* 종성이 object형인 경우 (2 단일 자음의 조합인 경우) */
196                    if (typeof JONG[jong] === 'object') {
197                        temp = temp.concat(JONG[jong]); // temp에 해당 종성의 자음들 추가
198                    /* 종성이 단일 자음으로 이루어진 경우 */
199                    } else {
200                        temp.push(JONG[jong]); // temp에 해당 자음 추가
201                    }
202                }
203            /* i번째 문자(code)가 완성된 한글이 아니면서 CONSONANTS의 멤버일 경우 (자음일 경우)*/    
204            } else if (_isConsonant(code)) {
205                if (_isCho(code)) {
206                    r = CHO[CHO_HASH[code]]; // 초성일 경우 해당 초성을 r에 저장
207                } else {
208                    r = JONG[JONG_HASH[code]]; // 종성일 경우 해당 종성을 r에 저장
209                }
210                if (typeof r === 'string') {
211                    temp.push(r); // r이 string 형일 경우 temp에 추가
212                } else {
213                    temp = temp.concat(r); // 아닐 경우 temp에 r 배열의 요소들 추가
214                }
215            /* i번째 문자(code)가 완성된 한글이 아니면서 COMPLETE_JUNG의 멤버일 경우 (중성일 경우) */
216            } else if (_isJung(code)) {
217                r = JUNG[JUNG_HASH[code]]; // r에 해당 중성 저장
218                if (typeof r === 'string') {
219                    temp.push(r); // r이 string 형일 경우 temp에 추가
220                } else {
221                    temp = temp.concat(r); // 아닐 경우 temp에 r 배열의 요소들 추가
222                }
223            /* i번째 문자(code)가 한글이 아닐 경우 */
224            } else {
225                temp.push(string.charAt(i)); // temp에 i번째 문자를 추가
226            }
227
228            if (grouped) result.push(temp); //grouped가 설정된 경우 result에 temp 추가
229            else result = result.concat(temp); //grouped가 설정되지 않은 경우 result에 temp의 요소들 추가
230        }
231
232        return result;
233    };
234
235    /* string으로 disassemle */
236    var disassembleToString = function (str) {
237        if (typeof str !== 'string') {
238            return ''; // 입력값이 string형이 아닐 경우 빈 문자열 반환
239        }
240        str = disassemble(str); // str을 disassemble
241        return str.join(''); // str을 문자열로 반환
242    };
243
244    /* string으로 assemble */
245    var assemble = function (array) {
246        if (typeof array === 'string') {
247            array = disassemble(array);
247 // 입력값이 string형인 경우 우선 disassemble
248        }
249
250        var result = [],
251            length = array.length,
252            code,
253            stage = 0,
254            complete_index = -1, //완성된 곳의 인덱스
255            previous_code,
256            jong_joined = false
257            ;
258
259        function _makeHangul(index) { // complete_index + 1부터 index까지를 greedy하게 한글로 만든다.
260            var code,
261                cho,
262                jung1,
263                jung2,
264                jong1 = 0,
265                jong2,
266                hangul = ''
267                ;
268
269            jong_joined = false;
270            if (complete_index + 1 > index) {
271                return;
272            }
273            for (var step = 1; ; step++) {
274                if (step === 1) {
275                    cho = array[complete_index + step].charCodeAt(0); // 첫 자모를 cho에 저장
276                    /* cho가 중성인 경우 */
277                    if (_isJung(cho)) { // 첫번째 것이 모음이면 1) ㅏ같은 경우이거나 2) ㅙ같은 경우이다
278                        /* cho의 다음 자모(jung1)가 범위 내에 있으면서 모음인 경우 */
279                        if (complete_index + step + 1 <= index && _isJung(jung1 = array[complete_index + step + 1].charCodeAt(0))) { //다음것이 있고 모음이면
280                            result.push(String.fromCharCode(_isJungJoinable(cho, jung1))); // cho와 jung1이 중성으로 조합가능한 경우 result에 조합한 문자 추가
281                            complete_index = index; // complete_index에 index값 저장 (index까지 assemble 완료)
282                            return;
283                        /* cho의 다음 자모가 없거나 자음인 경우 (cho와 결합할 것이 없을때)*/
284                        } else {
285                            result.push(array[complete_index + step]); // result에 cho에 해당하는 자모값 추가
286                            complete_index = index; // complete_index에 index값 저장 (index까지 assemble 완료)
287                            return;
288                        }
289                    /* cho가 중성이 아니면서 초성도 아닌 경우 */
290                    } else if (!_isCho(cho)) {
291                        result.push(array[complete_index + step]); // result에 cho에 해당하는 자모값 추가
292                        complete_index = index; // complete_index에 index값 저장 (index까지 assemble 완료)
293                        return;
294                    }
295                    hangul = array[complete_index + step]; // hangul에 첫 자모값 저장
296                } else if (step === 2) {
297                    jung1 = array[complete_index + step].charCodeAt(0); // jung1에 두번째 자모 저장
298                    /* jung1이 자음인 경우 */
299                    if (_isCho(jung1)) { //두번째 또 자음이 오면 ㄳ 에서 ㅅ같은 경우이다
300                        cho = _isJongJoinable(cho, jung1); // 앞의 초성(cho)과 jung1이 조합 가능한 경우 cho에 해당 조합을 저장한다
301                        hangul = String.fromCharCode(cho); // hangul에 cho를 문자열로 반환해 저장한다.
302                        result.push(hangul); // result에 hangul 추가
303                        complete_index = index; // complete_index에 index값 저장 (index까지 assemble 완료)
304                        return;
305                    /* jung1이 자음이 아닌 경우 */
306                    } else {
307                        hangul = String.fromCharCode((CHO_HASH[cho] * 21 + JUNG_HASH[jung1]) * 28 + HANGUL_OFFSET); // cho와 jung1을 한글로 조합해 문자열로 반환 후 hangul에 저장
308                    }
309                } else if (step === 3) {
310                    jung2 = array[complete_index + step].charCodeAt(0); // jung2에 세번째 자모 저장
311                    if (_isJungJoinable(jung1, jung2)) {
312                        jung1 = _isJungJoinable(jung1, jung2); // jung1과 jung2가 종성으로서 조합 가능한 경우 조합 해 jung1에 저장
313                    } else {
314                        jong1 = jung2; // jung1과 jung2가 종성으로서 조합 불가능한 경우 jung2값을 jong1에 저장
315                    }
316                    hangul = String.fromCharCode((CHO_HASH[cho] * 21 + JUNG_HASH[jung1]) * 28 + JONG_HASH[jong1] + HANGUL_OFFSET);
317                    
318                } else if (step === 4) {
319                    jong2 = array[complete_index + step].charCodeAt(0); // jong2에 네번째 자모 저장
320                    if (_isJongJoinable(jong1, jong2)) {
321                        jong1 = _isJongJoinable(jong1, jong2); // jong1과 jong2가 종성으로서 조합 가능한 경우 조합 후 jong1에 저장
322                    } else {
323                        jong1 = jong2; // jong1과 jong2가 종성으로서 조합 불가능한 경우 jong2값을 jong1에 저장
324                    }
325                    hangul = String.fromCharCode((CHO_HASH[cho] * 21 + JUNG_HASH[jung1]) * 28 + JONG_HASH[jong1] + HANGUL_OFFSET); // cho, jung1, jong1를 한글로 조합해 문자열로 반환 후 hangul에 저장
326                } else if (step === 5) {
327                    jong2 = array[complete_index + step].charCodeAt(0); // jong2에 다섯번째 자모 저장
328                    jong1 = _isJongJoinable(jong1, jong2); // jong1과 jong2를 종성으로서 조합해 jong1에 저장
329                    hangul = String.fromCharCode((CHO_HASH[cho] * 21 + JUNG_HASH[jung1]) * 28 + JONG_HASH[jong1] + HANGUL_OFFSET); // cho, jung1, jong1를 한글로 조합해 문자열로 반환 후 hangul에 저장
330                }
331
332                if (complete_index + step >= index) {
333                    result.push(hangul); // result에 hangul 추가 (조합 결과 추가)
334                    complete_index = index;
335                    return;
336                }
337            }
338        }
339        
340        /* 모든 문자에 대해 확인 */
341        for (var i = 0; i < length; i++) {
342            code = array[i].charCodeAt(0);
343            if (!_isCho(code) && !_isJung(code) && !_isJong(code)) { //초, 중, 종성 다 아니면
344                _makeHangul(i - 1); // i-1번째 문자까지 우선 한글로 조합한 후
345                _makeHangul(i); // i번째부터 다시 조합
346                stage = 0;
347                continue;
348            }
349            //console.log(stage, array[i]);
350            if (stage === 0) { // 초성이 올 차례
351                if (_isCho(code)) { // 초성이 오면 아무 문제 없다.
352                    stage = 1;
353                } else if (_isJung(code)) {
354                    // 중성이오면 ㅐ 또는 ㅘ 인것이다. 바로 구분을 못한다. 따라서 특수한 stage인 stage4로 이동
355                    stage = 4;
356                }
357            } else if (stage == 1) { //중성이 올 차례
358                if (_isJung(code)) { //중성이 오면 문제없음 진행.
359                    stage = 2;
360                } else { //아니고 자음이오면 ㄻ같은 경우가 있고 ㄹㅋ같은 경우가 있다.
361                    if (_isJongJoinable(previous_code, code)) {
362                        // 합쳐질 수 있다면 ㄻ 같은 경우인데 이 뒤에 모음이 와서 ㄹ마 가 될수도 있고 초성이 올 수도 있다. 따라서 섣불리 완성할 수 없다. 이땐 stage5로 간다.
363                        stage = 5;
364                    } else { //합쳐질 수 없다면 앞 글자 완성 후 여전히 중성이 올 차례
365                        _makeHangul(i - 1);
366                    }
367                }
368            } else if (stage == 2) { //종성이 올 차례
369                if (_isJong(code)) { //종성이 오면 다음엔 자음 또는 모음이 온다.
370                    stage = 3;
371                } else if (_isJung(code)) { //그런데 중성이 오면 앞의 모음과 합칠 수 있는지 본다.
372                    if (_isJungJoinable(previous_code, code)) { //합칠 수 있으면 여전히 종성이 올 차례고 그대로 진행
373                    } else { // 합칠 수 없다면 오타가 생긴 경우
374                        _makeHangul(i - 1);
375                        stage = 4;
376                    }
377                } else { // 받침이 안되는 자음이 오면 ㄸ 같은 이전까지 완성하고 다시시작
378                    _makeHangul(i - 1);
379                    stage = 1;
380                }
381            } else if (stage == 3) { // 종성이 하나 온 상태.
382                if (_isJong(code)) { // 또 종성이면 합칠수 있는지 본다.
383                    if (!jong_joined && _isJongJoinable(previous_code, code)) { //합칠 수 있으면 계속 진행. 왜냐하면 이번에 온 자음이 다음 글자의 초성이 될 수도 있기 때문. 대신 이 기회는 한번만
384                        jong_joined = true;
385                    } else { //없으면 한글자 완성
386                        _makeHangul(i - 1);
387                        stage = 1; // 이 종성이 초성이 되고 중성부터 시작
388                    }
389                } else if (_isCho(code)) { // 초성이면 한글자 완성.
390                    _makeHangul(i - 1);
391                    stage = 1; //이 글자가 초성이되므로 중성부터 시작
392                } else if (_isJung(code)) { // 중성이면 이전 종성은 이 중ì
392„±ê³¼ 합쳐지고 앞 글자는 받침이 없다.
393                    _makeHangul(i - 2);
394                    stage = 2;
395                }
396            } else if (stage == 4) { // 중성이 하나 온 상태
397                if (_isJung(code)) { //중성이 온 경우
398                    if (_isJungJoinable(previous_code, code)) { //이전 중성과 합쳐질 수 있는 경우
399                        _makeHangul(i);
400                        stage = 0;
401                    } else { //중성이 왔지만 못합치는 경우. ㅒㅗ 같은
402                        _makeHangul(i - 1);
403                    }
404                } else { // 아니면 자음이 온 경우.
405                    _makeHangul(i - 1);
406                    stage = 1;
407                }
408            } else if (stage == 5) { // 초성이 연속해서 두개 온 상태 ㄺ
409                if (_isJung(code)) { //이번에 중성이면 ㄹ가
410                    _makeHangul(i - 2);
411                    stage = 2;
412                } else {
413                    _makeHangul(i - 1);
414                    stage = 1;
415                }
416            }
417            previous_code = code;
418        }
419        _makeHangul(i - 1);
420        return result.join('');
421    };
422
423    var search = function (a, b) {
424        /* a 와 b 를 disassemble한 후 문자열로 반환해 ad, bd에 각각 저장 */
425        var ad = disassemble(a).join(''),
426            bd = disassemble(b).join('')
427            ;
428
429        return ad.indexOf(bd); // ad 에서 bd가 포함되는 인덱스를 찾아 반환
430    };
431
432    var rangeSearch = function (haystack, needle) {
433        var hex = disassemble(haystack).join(''),
434            nex = disassemble(needle).join(''),
435            grouped = disassemble(haystack, true),
436            re = new RegExp(nex, 'gi'),
437            indices = [],
438            result;
439
440        if (!needle.length) return [];
441
442        while ((result = re.exec(hex))) {
443            indices.push(result.index);
444        }
445
446        function findStart(index) {
447            for (var i = 0, length = 0; i < grouped.length; ++i) {
448                length += grouped[i].length;
449                if (index < length) return i;
450            }
451        }
452
453        function findEnd(index) {
454            for (var i = 0, length = 0; i < grouped.length; ++i) {
455                length += grouped[i].length;
456                if (index + nex.length <= length) return i;
457            }
458        }
459
460        return indices.map(function (i) {
461            return [findStart(i), findEnd(i)];
462        });
463    };
464
465    function Searcher(string) {
466        this.string = string;
467        this.disassembled = disassemble(string).join('');
468    }
469
470    Searcher.prototype.search = function (string) {
471        return disassemble(string).join('').indexOf(this.disassembled);
472    };
473    /* string이 자음으로 끝나는지 확인 */
474    var endsWithConsonant = function (string) {
475        if (typeof string === 'object') {
476            string = string.join('');
477        }
478
479        var code = string.charCodeAt(string.length - 1);
480
481        if (_isHangul(code)) { // 완성된 한글이면
482            code -= HANGUL_OFFSET;
483            var jong = code % 28;
484            if (jong > 0) {
485                return true;
486            }
487        } else if (_isConsonant(code)) { //자음이면
488            return true;
489        }
490        return false;
491    };
492
493    /* string이 target 문자로 끝나는지 확인 */
494    var endsWith = function (string, target) {
495        return disassemble(string).pop() === target;
496    };
497
498
499    var hangul = {
500        disassemble: disassemble,
501        d: disassemble, // alias for disassemble
502        disassembleToString: disassembleToString,
503        ds: disassembleToString, // alias for disassembleToString
504        assemble: assemble,
505        a: assemble, // alias for assemble
506        search: search,
507        rangeSearch: rangeSearch,
508        Searcher: Searcher,
509        endsWithConsonant: endsWithConsonant,
510        endsWith: endsWith,
511        isHangul: function (c) {
512            if (typeof c === 'string')
513                c = c.charCodeAt(0);
514            return _isHangul(c);
515        },
516        isComplete: function (c) {
517            if (typeof c === 'string')
518                c = c.charCodeAt(0);
519            return _isHangul(c);
520        },
521        isConsonant: function (c) {
522            if (typeof c === 'string')
523                c = c.charCodeAt(0);
524            return _isConsonant(c);
525        },
526        isVowel: function (c) {
527            if (typeof c === 'string')
528                c = c.charCodeAt(0);
529            return _isJung(c);
530        },
531        isCho: function (c) {
532            if (typeof c === 'string')
533                c = c.charCodeAt(0);
534            return _isCho(c);
535        },
536        isJong: function (c) {
537            if (typeof c === 'string')
538                c = c.charCodeAt(0);
539            return _isJong(c);
540        },
541        isHangulAll: function (str) {
542            if (typeof str !== 'string') return false;
543            for (var i = 0; i < str.length; i++) {
544                if (!_isHangul(str.charCodeAt(i))) return false;
545            }
546            return true;
547        },
548        isCompleteAll: function (str) {
549            if (typeof str !== 'string') return false;
550            for (var i = 0; i < str.length; i++) {
551                if (!_isHangul(str.charCodeAt(i))) return false;
552            }
553            return true;
554        },
555        isConsonantAll: function (str) {
556            if (typeof str !== 'string') return false;
557            for (var i = 0; i < str.length; i++) {
558                if (!_isConsonant(str.charCodeAt(i))) return false;
559            }
560            return true;
561        },
562        isVowelAll: function (str) {
563            if (typeof str !== 'string') return false;
564            for (var i = 0; i < str.length; i++) {
565                if (!_isJung(str.charCodeAt(i))) return false;
566            }
567            return true;
568        },
569        isChoAll: function (str) {
570            if (typeof str !== 'string') return false;
571            for (var i = 0; i < str.length; i++) {
572                if (!_isCho(str.charCodeAt(i))) return false;
573            }
574            return true;
575        },
576        isJongAll: function (str) {
577            if (typeof str !== 'string') return false;
578            for (var i = 0; i < str.length; i++) {
579                if (!_isJong(str.charCodeAt(i))) return false;
580            }
581            return true;
582        }
583    };
584
585    if (typeof define == 'function' && define.amd) {
586        define(function () {
587            return hangul;
588        });
589    } else if (typeof module !== 'undefined') {
590        module.exports = hangul;
591    } else {
592        window.Hangul = hangul;
593    }
594})();
595

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.