hangul.js

한글js

Αυτός ο κώδικας δεν πρέπει να εγκατασταθεί άμεσα. Είναι μια βιβλιοθήκη για άλλους κώδικες που περιλαμβάνεται μέσω της οδηγίας meta // @require https://update.greatest.deepsurf.us/scripts/22174/140927/hanguljs.js

  1. /**
  2. * Hangul.js
  3. * https://github.com/e-/Hangul.js
  4. *
  5. * Copyright 2015, Jaemin Jo
  6. * under the MIT license.
  7. */
  8.  
  9. (function(){
  10. 'use strict';
  11. var CHO = [
  12. 'ㄱ', 'ㄲ', 'ㄴ', 'ㄷ', 'ㄸ',
  13. 'ㄹ', 'ㅁ', 'ㅂ', 'ㅃ', 'ㅅ', 'ㅆ',
  14. 'ㅇ', 'ㅈ', 'ㅉ', 'ㅊ', 'ㅋ', 'ㅌ',
  15. 'ㅍ', 'ㅎ'
  16. ],
  17. JUNG = [
  18. 'ㅏ', 'ㅐ', 'ㅑ', 'ㅒ', 'ㅓ',
  19. 'ㅔ', 'ㅕ', 'ㅖ', 'ㅗ', ['ㅗ', 'ㅏ'], ['ㅗ', 'ㅐ'],
  20. ['ㅗ', 'ㅣ'], 'ㅛ', 'ㅜ', ['ㅜ','ㅓ'], ['ㅜ','ㅔ'], ['ㅜ','ㅣ'],
  21. 'ㅠ', 'ㅡ', ['ㅡ', 'ㅣ'], 'ㅣ'
  22. ],
  23. JONG = [
  24. '', 'ㄱ', 'ㄲ', ['ㄱ','ㅅ'], 'ㄴ', ['ㄴ','ㅈ'], ['ㄴ', 'ㅎ'], 'ㄷ', 'ㄹ',
  25. ['ㄹ', 'ㄱ'], ['ㄹ','ㅁ'], ['ㄹ','ㅂ'], ['ㄹ','ㅅ'], ['ㄹ','ㅌ'], ['ㄹ','ㅍ'], ['ㄹ','ㅎ'], 'ㅁ',
  26. 'ㅂ', ['ㅂ','ㅅ'], 'ㅅ', 'ㅆ', 'ㅇ', 'ㅈ', 'ㅊ', 'ㅋ', 'ㅌ', 'ㅍ', 'ㅎ'
  27. ],
  28. HANGUL_OFFSET = 0xAC00,
  29. CONSONANTS = [
  30. 'ㄱ', 'ㄲ', 'ㄳ', 'ㄴ', 'ㄵ', 'ㄶ', 'ㄷ', 'ㄸ',
  31. 'ㄹ', 'ㄺ', 'ㄻ', 'ㄼ', 'ㄽ', 'ㄾ', 'ㄿ', 'ㅀ',
  32. 'ㅁ', 'ㅂ', 'ㅃ', 'ㅄ', 'ㅅ', 'ㅆ', 'ㅇ', 'ㅈ',
  33. 'ㅉ', 'ㅊ', 'ㅋ', 'ㅌ', 'ㅍ', 'ㅎ'
  34. ],
  35. COMPLETE_CHO = [
  36. 'ㄱ', 'ㄲ', 'ㄴ', 'ㄷ', 'ㄸ',
  37. 'ㄹ', 'ㅁ', 'ㅂ', 'ㅃ', 'ㅅ', 'ㅆ',
  38. 'ㅇ', 'ㅈ', 'ㅉ', 'ㅊ', 'ㅋ', 'ㅌ', 'ㅍ', 'ㅎ'
  39. ],
  40. COMPLETE_JUNG = [
  41. 'ㅏ', 'ㅐ', 'ㅑ', 'ㅒ', 'ㅓ',
  42. 'ㅔ', 'ㅕ', 'ㅖ', 'ㅗ', 'ㅘ', 'ㅙ',
  43. 'ㅚ', 'ㅛ', 'ㅜ', 'ㅝ', 'ㅞ', 'ㅟ',
  44. 'ㅠ', 'ㅡ', 'ㅢ', 'ㅣ'
  45. ],
  46. COMPLETE_JONG = [
  47. '', 'ㄱ', 'ㄲ', 'ㄳ', 'ㄴ', 'ㄵ', 'ㄶ', 'ㄷ', 'ㄹ',
  48. 'ㄺ', 'ㄻ', 'ㄼ', 'ㄽ', 'ㄾ', 'ㄿ', 'ㅀ', 'ㅁ',
  49. 'ㅂ', 'ㅄ', 'ㅅ', 'ㅆ', 'ㅇ', 'ㅈ', 'ㅊ', 'ㅋ', 'ㅌ', 'ㅍ', 'ㅎ'
  50. ],
  51. COMPLEX_CONSONANTS = [
  52. ['ㄱ','ㅅ','ㄳ'],
  53. ['ㄴ','ㅈ','ㄵ'],
  54. ['ㄴ','ㅎ','ㄶ'],
  55. ['ㄹ','ㄱ','ㄺ'],
  56. ['ㄹ','ㅁ','ㄻ'],
  57. ['ㄹ','ㅂ','ㄼ'],
  58. ['ㄹ','ㅅ','ㄽ'],
  59. ['ㄹ','ㅌ','ㄾ'],
  60. ['ㄹ','ㅍ','ㄿ'],
  61. ['ㄹ','ㅎ','ㅀ'],
  62. ['ㅂ','ㅅ','ㅄ']
  63. ],
  64. COMPLEX_VOWELS = [
  65. ['ㅗ','ㅏ','ㅘ'],
  66. ['ㅗ','ㅐ','ㅙ'],
  67. ['ㅗ','ㅣ','ㅚ'],
  68. ['ㅜ','ㅓ','ㅝ'],
  69. ['ㅜ','ㅔ','ㅞ'],
  70. ['ㅜ','ㅣ','ㅟ'],
  71. ['ㅡ','ㅣ','ㅢ']
  72. ],
  73. CONSONANTS_HASH,
  74. CHO_HASH,
  75. JUNG_HASH,
  76. JONG_HASH,
  77. COMPLEX_CONSONANTS_HASH,
  78. COMPLEX_VOWELS_HASH
  79. ;
  80.  
  81.  
  82. function _makeHash(array){
  83. var length = array.length,
  84. hash = {0 : 0}
  85. ;
  86. for (var i = 0; i < length; i++) {
  87. if(array[i])
  88. hash[array[i].charCodeAt(0)] = i;
  89. }
  90. return hash;
  91. }
  92.  
  93. CONSONANTS_HASH = _makeHash(CONSONANTS);
  94. CHO_HASH = _makeHash(COMPLETE_CHO);
  95. JUNG_HASH = _makeHash(COMPLETE_JUNG);
  96. JONG_HASH = _makeHash(COMPLETE_JONG);
  97.  
  98. function _makeComplexHash(array){
  99. var length = array.length,
  100. hash = {},
  101. code1,
  102. code2
  103. ;
  104. for (var i = 0; i < length; i++) {
  105. code1 = array[i][0].charCodeAt(0);
  106. code2 = array[i][1].charCodeAt(0);
  107. if (typeof hash[code1] === 'undefined') {
  108. hash[code1] = {};
  109. }
  110. hash[code1][code2] = array[i][2].charCodeAt(0);
  111. }
  112. return hash;
  113. }
  114.  
  115. COMPLEX_CONSONANTS_HASH = _makeComplexHash(COMPLEX_CONSONANTS);
  116. COMPLEX_VOWELS_HASH = _makeComplexHash(COMPLEX_VOWELS);
  117.  
  118. function _isConsonant(c) {
  119. return CONSONANTS_HASH[c];
  120. }
  121.  
  122. function _isCho(c){
  123. return typeof CHO_HASH[c] !== 'undefined';
  124. }
  125.  
  126. function _isJung(c){
  127. return typeof JUNG_HASH[c] !== 'undefined';
  128. }
  129.  
  130. function _isJong(c){
  131. return typeof JONG_HASH[c] !== 'undefined';
  132. }
  133.  
  134. function _isHangul(c /* code number */){
  135. return 0xAC00 <= c && c <= 0xd7a3;
  136. }
  137.  
  138. function _isJungJoinable(a,b){
  139. return (COMPLEX_VOWELS_HASH[a] && COMPLEX_VOWELS_HASH[a][b]) ? COMPLEX_VOWELS_HASH[a][b] : false;
  140. }
  141.  
  142. function _isJongJoinable(a,b){
  143. return COMPLEX_CONSONANTS_HASH[a] && COMPLEX_CONSONANTS_HASH[a][b] ? COMPLEX_CONSONANTS_HASH[a][b] : false;
  144. }
  145.  
  146. var disassemble = function(string){
  147. if (typeof string === 'object') {
  148. string = string.join('');
  149. }
  150.  
  151. var result = [],
  152. length = string.length,
  153. cho,
  154. jung,
  155. jong,
  156. code,
  157. r
  158. ;
  159.  
  160. for (var i = 0; i < length; i++) {
  161. code = string.charCodeAt(i);
  162. if (_isHangul(code)) { // 완성된 한글이면
  163. code -= HANGUL_OFFSET;
  164. jong = code % 28;
  165. jung = (code - jong) / 28 % 21;
  166. cho = parseInt((code - jong) / 28 / 21);
  167. result.push(CHO[cho]);
  168. if (typeof JUNG[jung] === 'object') {
  169. result = result.concat(JUNG[jung]);
  170. } else {
  171. result.push(JUNG[jung]);
  172. }
  173. if (jong > 0) {
  174. if(typeof JONG[jong] === 'object') {
  175. result = result.concat(JONG[jong]);
  176. } else {
  177. result.push(JONG[jong]);
  178. }
  179. }
  180. } else if (_isConsonant(code)) { //자음이면
  181. if (_isCho(code)) {
  182. r = CHO[CHO_HASH[code]];
  183. } else {
  184. r = JONG[JONG_HASH[code]];
  185. }
  186. if (typeof r == 'string') {
  187. result.push(r);
  188. } else {
  189. result = result.concat(r);
  190. }
  191. } else if (_isJung(code)) {
  192. r = JUNG[JUNG_HASH[code]];
  193. if (typeof r == 'string') {
  194. result.push(r);
  195. } else {
  196. result = result.concat(r);
  197. }
  198. } else {
  199. result.push(string.charAt(i));
  200. }
  201. }
  202. return result;
  203. };
  204.  
  205. var assemble = function(array){
  206. if (typeof array === 'string') {
  207. array = disassemble(array);
  208. }
  209.  
  210. var result = [],
  211. length = array.length,
  212. code ,
  213. stage = 0,
  214. complete_index = -1, //완성된 곳의 인덱스
  215. previous_code
  216. ;
  217.  
  218. function _makeHangul(index){ // complete_index + 1부터 index까지를 greedy하게 한글로 만든다.
  219. var code,
  220. cho,
  221. jung1,
  222. jung2,
  223. jong1 = 0,
  224. jong2,
  225. hangul = ''
  226. ;
  227. if (complete_index + 1 > index) {
  228. return;
  229. }
  230. for (var step = 1; ; step++) {
  231. if (step === 1) {
  232. cho = array[complete_index + step].charCodeAt(0);
  233. if (_isJung(cho)) { // 첫번째 것이 모음이면 1) ㅏ같은 경우이거나 2) ㅙ같은 경우이다
  234. if (complete_index + step + 1 <= index && _isJung(jung1 = array[complete_index + step + 1].charCodeAt(0))) { //다음것이 있고 모음이면
  235. result.push(String.fromCharCode(_isJungJoinable(cho, jung1)));
  236. complete_index = index;
  237. return;
  238. } else {
  239. result.push(array[complete_index + step]);
  240. complete_index = index;
  241. return;
  242. }
  243. } else if (!_isCho(cho)) {
  244. result.push(array[complete_index + step]);
  245. complete_index = index;
  246. return;
  247. }
  248. hangul = array[complete_index + step];
  249. } else if (step === 2) {
  250. jung1 = array[complete_index + step].charCodeAt(0);
  251. if (_isCho(jung1)) { //두번째 또 자음이 오면 ㄳ 에서 ㅅ같은 경우이다
  252. cho = _isJongJoinable(cho, jung1);
  253. hangul = String.fromCharCode(cho);
  254. result.push(hangul);
  255. complete_index = index;
  256. return;
  257. } else {
  258. hangul = String.fromCharCode((CHO_HASH[cho] * 21 + JUNG_HASH[jung1]) * 28 + HANGUL_OFFSET);
  259. }
  260. } else if (step === 3) {
  261. jung2 = array[complete_index + step].charCodeAt(0);
  262. if (_isJungJoinable(jung1, jung2)) {
  263. jung1 = _isJungJoinable(jung1, jung2);
  264. } else {
  265. jong1 = jung2;
  266. }
  267. hangul = String.fromCharCode((CHO_HASH[cho] * 21 + JUNG_HASH[jung1]) * 28 + JONG_HASH[jong1] + HANGUL_OFFSET);
  268. } else if (step === 4) {
  269. jong2 = array[complete_index + step].charCodeAt(0);
  270. if (_isJongJoinable(jong1, jong2)) {
  271. jong1 = _isJongJoinable(jong1, jong2);
  272. } else {
  273. jong1 = jong2;
  274. }
  275. hangul = String.fromCharCode((CHO_HASH[cho] * 21 + JUNG_HASH[jung1]) * 28 + JONG_HASH[jong1] + HANGUL_OFFSET);
  276. } else if (step === 5) {
  277. jong2 = array[complete_index + step].charCodeAt(0);
  278. jong1 = _isJongJoinable(jong1, jong2);
  279. hangul = String.fromCharCode((CHO_HASH[cho] * 21 + JUNG_HASH[jung1]) * 28 + JONG_HASH[jong1] + HANGUL_OFFSET);
  280. }
  281.  
  282. if (complete_index + step >= index) {
  283. result.push(hangul);
  284. complete_index = index;
  285. return;
  286. }
  287. }
  288. }
  289.  
  290. for (var i = 0 ; i < length ; i++) {
  291. code = array[i].charCodeAt(0);
  292. if (!_isCho(code) && !_isJung(code) && !_isJong(code)){ //초, 중, 종성 다 아니면
  293. _makeHangul(i-1);
  294. _makeHangul(i);
  295. stage = 0;
  296. continue;
  297. }
  298. //console.log(stage, array[i]);
  299. if (stage === 0) { // 초성이 올 차례
  300. if (_isCho(code)) { // 초성이 오면 아무 문제 없다.
  301. stage = 1;
  302. } else if (_isJung(code)) {
  303. // 중성이오면 ㅐ 또는 ㅘ 인것이다. 바로 구분을 못한다. 따라서 특수한 stage인 stage4로 이동
  304. stage = 4;
  305. }
  306. } else if (stage == 1) { //중성이 올 차례
  307. if (_isJung(code)) { //중성이 오면 문제없음 진행.
  308. stage = 2;
  309. } else { //아니고 자음이오면 ㄻ같은 경우가 있고 ㄹㅋ같은 경우가 있다.
  310. if (_isJongJoinable(previous_code, code)) {
  311. // 합쳐질 수 있다면 ㄻ 같은 경우인데 이 뒤에 모음이 와서 ㄹ마 가 될수도 있고 초성이 올 수도 있다. 따라서 섣불리 완성할 수 없다. 이땐 stage5로 간다.
  312. stage = 5;
  313. } else { //합쳐질 수 없다면 앞 글자 완성 후 여전히 중성이 올 차례
  314. _makeHangul(i-1);
  315. }
  316. }
  317. } else if (stage == 2) { //종성이 올 차례
  318. if (_isJong(code)) { //종성이 오면 다음엔 자음 또는 모음이 온다.
  319. stage = 3;
  320. } else if (_isJung(code)) { //그런데 중성이 오면 앞의 모음과 합칠 수 있는지 본다.
  321. if (_isJungJoinable(previous_code, code)) { //합칠 수 있으면 여전히 종성이 올 차례고 그대로 진행
  322. } else { // 합칠 수 없다면 오타가 생긴 경우
  323. _makeHangul(i-1);
  324. stage = 4;
  325. }
  326. } else { // 받침이 안되는 자음이 오면 ㄸ 같은 이전까지 완성하고 다시시작
  327. _makeHangul(i-1);
  328. stage = 1;
  329. }
  330. } else if (stage == 3) { // 종성이 하나 온 상태.
  331. if (_isJong(code)) { // 또 종성이면 합칠수 있는지 본다.
  332. if (_isJongJoinable(previous_code, code)) { //합칠 수 있으면 계속 진행. 왜냐하면 이번에 온 자음이 다음 글자의 초성이 될 수도 있기 때문
  333. } else { //없으면 한글자 완성
  334. _makeHangul(i-1);
  335. stage = 1; // 이 종성이 초성이 되고 중성부터 시작
  336. }
  337. } else if (_isCho(code)) { // 초성이면 한글자 완성.
  338. _makeHangul(i-1);
  339. stage = 1; //이 글자가 초성이되므로 중성부터 시작
  340. } else if (_isJung(code)) { // 중성이면 이전 종성은 이 중성과 합쳐지고 앞 글자는 받침이 없다.
  341. _makeHangul(i-2);
  342. stage = 2;
  343. }
  344. } else if (stage == 4) { // 중성이 하나 온 상태
  345. if (_isJung(code)) { //중성이 온 경우
  346. if(_isJungJoinable(previous_code, code)) { //이전 중성과 합쳐질 수 있는 경우
  347. _makeHangul(i);
  348. stage = 0;
  349. } else { //중성이 왔지만 못합치는 경우. ㅒㅗ 같은
  350. _makeHangul(i-1);
  351. }
  352. } else { // 아니면 자음이 온 경우.
  353. _makeHangul(i-1);
  354. stage = 1;
  355. }
  356. } else if (stage == 5) { // 초성이 연속해서 두개 온 상태 ㄺ
  357. if (_isJung(code)) { //이번에 중성이면 ㄹ가
  358. _makeHangul(i-2);
  359. stage = 2;
  360. } else {
  361. _makeHangul(i-1);
  362. stage = 1;
  363. }
  364. }
  365. previous_code = code;
  366. }
  367. _makeHangul(i-1);
  368. return result.join('');
  369. };
  370.  
  371. var search = function(a, b){
  372. var ad = disassemble(a).join(''),
  373. bd = disassemble(b).join('')
  374. ;
  375.  
  376. return ad.indexOf(bd);
  377. };
  378.  
  379. function Searcher(string) {
  380. this.string = string;
  381. this.disassembled = disassemble(string).join('');
  382. }
  383.  
  384. Searcher.prototype.search = function(string) {
  385. return disassemble(string).join('').indexOf(this.disassembled);
  386. };
  387.  
  388. var endsWithConsonant = function (string) {
  389. if (typeof string === 'object') {
  390. string = string.join('');
  391. }
  392.  
  393. var code = string.charCodeAt(string.length - 1);
  394.  
  395. if (_isHangul(code)) { // 완성된 한글이면
  396. code -= HANGUL_OFFSET;
  397. var jong = code % 28;
  398. if (jong > 0) {
  399. return true;
  400. }
  401. } else if ((typeof _isConsonant(code)) !== 'undefined') { //자음이면
  402. return true;
  403. }
  404. return false;
  405. };
  406.  
  407. var hangul = {
  408. disassemble: disassemble,
  409. assemble: assemble,
  410. search: search,
  411. Searcher: Searcher,
  412. endsWithConsonant: endsWithConsonant,
  413. isHangul: function(c){
  414. if (typeof c === 'string')
  415. c = c.charCodeAt(0);
  416. return _isHangul(c);
  417. },
  418. isConsonant: function(c){
  419. if (typeof c === 'string')
  420. c = c.charCodeAt(0);
  421. return (typeof _isConsonant(c)) !== 'undefined';
  422. },
  423. isVowel: function(c){
  424. if (typeof c === 'string')
  425. c = c.charCodeAt(0);
  426. return _isJung(c);
  427. },
  428. isCho: function(c){
  429. if (typeof c === 'string')
  430. c = c.charCodeAt(0);
  431. return _isCho(c);
  432.  
  433. },
  434. isJong: function(c){
  435. if (typeof c === 'string')
  436. c = c.charCodeAt(0);
  437. return _isJong(c);
  438. }
  439. };
  440.  
  441. if (typeof define == 'function' && define.amd) {
  442. define(function(){
  443. return hangul;
  444. });
  445. } else if (typeof module !== 'undefined') {
  446. module.exports = hangul;
  447. } else {
  448. window.Hangul = hangul;
  449. }
  450. })();
  451.  
  452. var toKorChars = function(string, onlyCho) {
  453. onlyCho = onlyCho || false;
  454. var cCho = [ 'ㄱ', 'ㄲ', 'ㄴ', 'ㄷ', 'ㄸ', 'ㄹ', 'ㅁ', 'ㅂ', 'ㅃ', 'ㅅ', 'ㅆ', 'ㅇ', 'ㅈ', 'ㅉ', 'ㅊ', 'ㅋ', 'ㅌ', 'ㅍ', 'ㅎ' ],
  455. cJung = [ 'ㅏ', 'ㅐ', 'ㅑ', 'ㅒ', 'ㅓ', 'ㅔ', 'ㅕ', 'ㅖ', 'ㅗ', 'ㅘ', 'ㅙ', 'ㅚ', 'ㅛ', 'ㅜ', 'ㅝ', 'ㅞ', 'ㅟ', 'ㅠ', 'ㅡ', 'ㅢ', 'ㅣ' ],
  456. cJong = [ '', 'ㄱ', 'ㄲ', 'ㄳ', 'ㄴ', 'ㄵ', 'ㄶ', 'ㄷ', 'ㄹ', 'ㄺ', 'ㄻ', 'ㄼ', 'ㄽ', 'ㄾ', 'ㄿ', 'ㅀ', 'ㅁ', 'ㅂ', 'ㅄ', 'ㅅ', 'ㅆ', 'ㅇ', 'ㅈ', 'ㅊ', 'ㅋ', 'ㅌ', 'ㅍ', 'ㅎ' ],
  457. cho, jung, jong;
  458.  
  459. var str = string,
  460. cnt = str.length,
  461. chars = [],
  462. cCode;
  463.  
  464. for (var i = 0; i < cnt; i++) {
  465. cCode = str.charCodeAt(i);
  466.  
  467. if (cCode == 32) { continue; }
  468.  
  469. // 한글이 아닌 경우
  470. if (cCode < 0xAC00 || cCode > 0xD7A3) {
  471. chars.push(str.charAt(i));
  472. continue;
  473. }
  474.  
  475. cCode = str.charCodeAt(i) - 0xAC00;
  476.  
  477. jong = cCode % 28; // 종성
  478. jung = ((cCode - jong) / 28 ) % 21; // 중성
  479. cho = (((cCode - jong) / 28 ) - jung ) / 21; // 초성
  480.  
  481. chars.push(cCho[cho]);
  482.  
  483. if (onlyCho)
  484. {
  485. continue;
  486. } else
  487. {
  488. chars.push(cJung[jung]);
  489.  
  490. if (cJong[jong] !== '')
  491. {
  492. chars.push(cJong[jong]);
  493. }
  494. }
  495. }
  496. return chars;
  497. };
  498. /** end of Hangul.js */