Pro Yearly is on sale from $80 to $50! »

유니코드 스터디

유니코드 스터디

스포카 크리에이터팀에서 발표한 유니코드 소개 자료입니다. 대상은 디자이너와 프로그래머입니다. 의도적으로 너무 기술적인 내용은 뺐습니다. 이하는 발표자 노트입니다.

Slide 1: 스포카 크리에이터팀이 다같이 듣는 유니코드 소개. 발표자는 Hong.

Slide 2: 지난해 말 일본 지사 설립하고, 올해부터 일본에서도 영업중.
일본 외에도 이른바 “중국말하는 일본”인 대만이나, 대표 Richard가 유년기를 보낸 홍콩, 혹은 그 외 동남아 국가에도 도도 포인트를 팔아보자는 얘기가 회사 안에서 종종 들리고 있음.

Slide 3: 작년부터 우리 팀 모든 사람이 항상 씨름하고 있는 주제.

Slide 4: 우선 지역화란 제품을 특정한 언어·문화권에서 쓸 수 있도록 고치는 작업을 말한다. 즉 한국어 버전 도도 포인트라는 제품이 우리에게 있는데, 이걸 일본에서도 팔기 위해서 일본어로 번역하고 일본 현지 사정에 맞게 기능을 손본 뒤에 일본어 버전 도도 포인트라는 제품으로 만드는 것. 이렇게 되면 제품은 둘이 된다. 한국어 버전 도도 포인트에 기능을 추가할 때마다 일본어 버전에서도 그걸 배껴서 붙여야 한다. 제품 유지 보수 비용 증가. “L10n”으로도 표기.

Slide 5: 반면 국제화는 하나의 제품이 여러 언어·문화권에서 쓸 수 있도록 만드는 것. 즉, 제품의 수를 늘리는 것이 아니라, 하나의 제품 안에서 지원하는 언어 등을 늘리는 것. 국제화 역시 제품의 유지 보수 비용을 증가시킨다. 하지만 지역화를 하는 것만큼 무리하게 증가시키는 것은 아니다. “I18n”으로도 표기. 우리 팀이 취해야 하는, 그리고 전부터 취해온 방식.

Slide 6: 유니코드가 다루는 대상 자체가 세계의 다양한 문자 및 표기들이고, 이는 우리가 제품을 만들 때도 활용할 수 있는 구성물들.
유니코드를 배우다보면 다른 나라 사람들은 글자를 오른쪽에서 왼쪽으로 쓰는구나, 세로 쓰기를 하는구나, 띄어쓰기를 안 하는구나, 소수점에 컴마를 쓰고 자릿수 구분에 오히려 점을 쓰는구나 같은 사실들을 자연스럽게 알게 된다.
유니코드는 복잡하고 방대하지만 다루려는 대상의 복잡함에 비하면 감당할 수는 있을만큼 간단해지도록 잘 통제되어 있다. 이렇게 복잡하고 다양한 요구사항을 어떻게 대하는 지혜를 엿볼 수 있다.

Slide 7: 오늘은 디자이너도 참석하셨기 때문에 UTF-8니 BOM이니 하는 바이트 인코딩 문제 같은 것들은 뺐습니다.

Slide 8:

Slide 9: 유니코드 컨소시엄에는 우리가 잘 아는 세계적인 소프트웨어 기업들이 두루 참여하고 있음.

요는, 우리보다 경험도 많고 지혜도 많은 사람들이다. 유니코드 컨소시엄의 전문가들은 우리보다 더 잘 안다.

Slide 10: 유니코드가 다루는 대상은 주로 문자에 관계된 것으로 한정된다. 컴퓨터에 문자를 저장하고, 컴퓨터가 그 문자들을 다른 문자로 가공하는 일을 도와준다. 가령 모든 대문자를 소문자로 바꾸려고 하면 프로그래머들은 영어에서 쓰는 알파벳 문자는 금방 떠올리지만, 독일 등에서 쓰는 Ä 같이 움라우트 붙은 대문자들을 ä 같은 움라우트 붙은 소문자로 바꿔야 한다는 것은 쉽게 놓친다. 이러한 지식의 부재는 소프트웨어를 국제화할 때 문제를 만든다. 유니코드는 그러한 구체적인 지식을 모든 프로그래머가 알고 있지 못해도 문자를 가공하는 프로그램을 올바르게 짤 수 있게 도와준다.

CLDR은 나중에 다룬다.

Slide 11: 반면 유니코드는 언어에 관해서는 크게 다루지 않는다. 유니코드는 “가” 문자가 한글이라는 정보는 가지고 있지만, 한국어를 표기할 때 쓰인다는 정보는 가지고 있지 않다. 로마자는 영어, 프랑스어, 독일어 등에서 두루 쓰이지만, 유니코드는 A 문자가 그러한 언어들을 표기할 때 쓰인다는 정보는 갖지 않는다. 그냥 A가 로마자라는 정보만 갖는다.

또, 유니코드 표준 문서를 뒤지면 자주 나오는 표현이 “유니코드는 글리프가 아니라 문자를 부호화한다”, “유니코드는 글리프가 아니라 문자의 의미만 인코딩한다” 같은 것이다. 유니코드 표준 차트에는 예시를 위한 문자별 레퍼런스 글리프를 제공하긴 하지만, 문자의 글리프가 어떤 모양이어야 하는지에 대해서는 보장하지도, 요구하지도 않는다. 유니코드 문자를 어떤 글리프로 표현하는지는 전적으로 서체 디자이너가 결정한다.

따라서 당연히 유니코드는 서체 또한 다루지 않는다. 다만, 컴퓨터 서체 포맷은 내부적으로 각 글리프가 어떤 유니코드 문자를 표현하는 것인지 연결해둔 표를 갖고 있다.

Slide 12: “유니코드는 글리프가 아닌 문자를 부호화한다.”

Slide 13: 왜 유니코드는 수많은 같은 모양 글리프를 다른 문자로 만드는 걸까? 가령 로마자 비(B)와 그리스 문자 베타(Β)는 같은 글리프이며, 둘 모두 페니키아 문자에서 파생된 공통의 유래를 가지고 있으니 같은 문자도 봐도 무방한 것처럼 보인다.

Slide 14: 하지만 해당 문자를 소문자로 바꾸려고 하면 양상이 달라지며 문제가 드러난다. 로마 대문자 B와 그리스 대문자 Β는 같은 글리프지만, 그와 대응되는 각각의 소문자는 아주 다른 글리프로 표현되기 때문이다. 글리프 자체는 문자가 담는 의미 정보를 손실하기 때문에 그와 관계된 문자적 맥락이 사라져 버린다. 이는 연락처를 텍스트 대신 레스터 이미지로 만들면 긁어서 복사할 수도 없고 검색도 못하게 되는 것과 비슷한 문제이다.

당연하지만 로마 대문자 B와 그리스 대문자 Β가 같은 글리프여야 하는 것도 아니다. 폰트 디자이너는 그 둘에 서로 다른 글리프를 그려도 괜찮다.

Slide 15: 유니코드의 모든 문자는 코드포인트라 불리는 고유한 번호와, 고유한 이름이 부여되어 있다.

코드포인트는 보통 앞에 U+ 접두어를 붙이고, 그 뒤에 16진수를 써서 표기한다. 10진수가 아닌 16진수를 쓰는 이유는 프로그래머에게 그쪽이 경계를 구분하기 좋기 때문이다.

당연하지만 문자와 코드포인트를 외울 필요는 없다. 유니코드 사이트에 올라와 있는 차트에 다 나와 있고, 뒤에서 소개할 여러 프로그램이나 웹사이트로 쉽게 검색할 수 있다.

Slide 16: 이 외에도 상당히 다양한 성질이 있음. 프로그래머들 사이에서는 property라는 말이 더 친숙할지도.

Slide 17: 이렇게 배경이 까만 슬라이드는 프로그래머들만 보면 되는 내용.

가령 파이썬 3에서는 문자열이 모두 유니코드이다. 그래서 단순히 영어에서 쓰이는 알파벳 뿐만 아니라, 움라우트가 들어간 알파벳 같이 유럽의 여러 언어에서 쓰이는 모든 알파벳에 대해 case 처리가 된다. 다만 case라는 게 없는 문자에서는 아무런 변화도 없음.

Slide 18: 파이썬에서는 아라비아 숫자만 판별하는 str.isdigit() 메서드와 별개로, 유니코드에서 숫자로 보는 모든 문자를 판별하는 str.isnumeric()이 존재.

Slide 19: 파이썬 표준 라이브러리에는 unicodedata라는 모듈이 있는데, 이걸 사용하면 문자를 분해해볼 수 있다.

Slide 20: 히라가나와 가타카나가 일본어라는 하나의 스크립트에 묶이지 않고, 각각의 스크립트로 나뉘어 있는 것에 주의. 다시 강조하지만 유니코드는 언어를 다루는 것이 아니라 문자를 다룬다.

Slide 21: PyPI에 올라와 있는 uniscripts 패키지를 설치하면 어떤 유니코드 문자 혹은 문자열이 어떤 script에 포함되어 있는지 확인 가능.

Slide 22: 꼭 필요하면 쓰지만, 안 쓰는 게 좋음. 고정폭 서체를 쓸 때나 유용.

Slide 23: 역시 표준 라이브러리의 unicodedata 모듈을 쓰면 너비 계산도 가능.

Slide 24: 간단한 도구 실습도…

Slide 25: 죄송하다는 말씀밖에 드릴 말이 없습니다.

9ac051aa8b199b55b5da8aeb1679d71d?s=128

Hong Minhee

June 18, 2015
Tweet

Transcript

  1. 큲읺펞핂 퓮삖슪큲싢 뼒풢핊 짊

  2. 푆펞컪솒핳칺쁢큲 ˖ 뼒핊쫆힎칺컲잋 ˖ 뼒핺핊쫆펞컪솒솒핆폏펓훟 ˖ 핊쫆푆펞샎잚핂빦솧빶팒묻많슲솒˘

  3. 묻헪v힎펻v쩖펻 ˖ 맪픦삲읆맪뼞 ˖ 묻헪 JOUFSOBUJPOBMJ[BUJPO  ˖ 힎펻 MPDBMJ[BUJPO

     ˖ 쩖펻 USBOTMBUJPO
  4. 힎펻 ˖ 헪픒삲읆펆펂v줆뭚펞컪틆쿦핖멚삲 ˖ 묻핆핂컃픒핂푷쿦핖솒옫묻펞컪쁢컃믎픒삲 ˖ 솒솒핆읊핊쫆펞컪틆쿦핖솒옫핊쫆펂솒솒핆읊잚슮삲 ˖ 킪쁢헪핂펆펂v줆뭚쿦잚쁦펂빪삲

  5. 묻헪 ˖ 빦픦헪픒숦핂캏픦펺얺펆펂v줆뭚펞컪틆쿦핖멚삲 ˖ 잳픒칺졂픚픒쌚펂썲펆펂읊틆멑핆힎몮읊쿦핖멚삲 ˖ 솒솒핆읊컲쌚 샇잲핳펞컪펂썲펆펂읊틆힎몮읂솒옫삲 ˖ 펺얺빦않펞킪솒헪픎빦옪퓮힎쇪삲

  6. 퓮삖슪읊짾푾졂 ˖ 헪픒잚슲쌚삲묻펂v삲줆줆헪펞헟믊쁢짷킫헒짦픒숞욶짾풂삲 ˖ 믆뺳삲읆빦않칺앚슲핂펂쎉멚핋몮튾졂컪칺쁢힎솒잜핂팚쿦핖삲 ˖ 섲픊옪쫃핯삲퍟푢묺칺픒삲욶쁢힎솒짾풆쿦핖삲 ˖ 짾푾졂홙삲믾쫂삲쁢 졶읂졂핂헪헪좉잚슮삲

  7. 퓮삖슪뫃쭎픦펂엲풎 ˖ 퓇펞핞욚많잜밂힎잚묻펂핞욚쁢쭎혿 ˖ 콚풶펂쭒퍊펞컪핊쁢잜픎힏묾펞멚숞욶솒풎핂쇦힎잚˘ ˖ 옪믆앦젆빦핂잚믾쿮헏핆뺂푷핂컬펺핖펂컪멏픒훎삲 ˖ $+,퓮삖슪읊쫂삲쫂졂퓮삖슪뫃쭎핆힎핞뫃쭎핆힎졶읂멮삲

  8. 6OJDPEF ˖ *40묻헪훎 *40*&$  ˖ 뼒샎펞컿잋 ˖ 믆샇킪핂짆콚풶펂묻헪퐎틶읒섦펓슲핂훊 ˖

    퓮삖슪콚킪펒펞컪뫎읺
  9. 6OJDPEF$POTPSUJVN ˖ 푾읺많핦팒쁢훊푢쩲섢슲핂펺 ˖ "EPCF "QQMF (PPHMF *#. .JDSPTPGU 0SBDMF

    5XJUUFS :BIPP ˖ )VBXFJ 3BLVUFO ˖ 맏줆읊샎잚헒줆많슲 ˖ 펺얺콚풶펂쭒퍊읊샎잚헒줆많슲 ˖ 뼒샎펞핂짆켆몒헏픊옪헪픒빷컪묻헪펞핢쳖뭃픎헒줆많슲
  10. 퓮삖슪많삲욶쁢멑 ˖ 줆핞 ˖ 줆핞칺핂픦뫎몒 FHˑ"픦콚줆핞쁢B˒  ˖ 줆핞펞뫎훊쪎헣쫂 FHˑꆃ픎묻펂옪LVN뫊LJN픊옪짪픚˒

     ˖ 줆핞슲픦퓮푷줄픚 FHˑ많쁢믎˒ ˑמ쁢않많빦˒  ˖ 줆핞읊쿦옪쁢짷쩣 펞줆핞읊헎핳믾퓒  ˖ $-%3쩖펻펞푢뫎푷헏슲졶픚
  11. 퓮삖슪많삲욶힎팘쁢멑 ˖ 펆펂 ˖ 믎읺 HMZQI  ˖ 컪

  12. ˊ6OJDPEF'"2 “Unicode encodes characters, not glyphs.”

  13. # ü 옪잖핞찒 믆읺큲줆핞쩮

  14. C Ĕ 옪잖콚줆핞찒 믆읺큲콚줆핞쩮

  15. 줆핞 ˖ 맏줆핞펞쁢몮퓮쩖퐎핂읒핂핖삲 ˖ " U+0041 LATIN CAPITAL LETTER A

     ˖ 많 U+AC00 HANGUL SYLLABLE GA  ˖ 㣓 U+5929 CJK UNIFIED IDEOGRAPH-5929
  16. 줆핞픦컿힖 ˖ 펂썲줆핞슲픎DBTF않쁢멚핖삲"쁢B픦샎줆핞몮 B쁢"픦콚줆핞삲 ˖ 펂썲줆핞슲픎풎않푾 VNMBVU 많쭧픒쿦핖삲 FHƒ £

     ˖ 펂썲줆핞슲픎쭒쇮쿦핖삲 FH˳̔5. ݫ̔ 훊  ˖ 펂썲줆핞슲픎쿦읊씉삲 FH Ⱂ ̂  ˖ 줆핞슲픎콚읺뺂핋픒쿦핖삲 FH㣓픎잚삲읾펞컪UJÀO픊옪핋픚  ˖ 펂썲줆핞슲픎폲읆펞컪푊픊옪 픎퓒펞컪팒앦옪틂삲
  17. 샎콚줆핞 >>> 'A'.lower() 'a' >>> 'ä'.upper() 'Ä' >>> 'о'.lower() 'о'

    >>> ord('о'), ord('о'.lower()) (44032, 44032)
  18. 쿹핞 >>> '1'.isdigit() True >>> 'ᎂ'.isdigit() False >>> '1'.isnumeric() True

    >>> 'ᎂ'.isnumeric() True
  19. 쭒 >>> import unicodedata >>> unicodedata.decomposition('ā') '<compat> 0028 110C 116E

    0029' >>> list('\u0028\u110c\u116e\u0029') ['(', '䝶', '䞌', ')'] >>> '\u0028\u110c\u116e\u0029' '(઱)'
  20. 4DSJQU ˖ 퓮삖슪펞컪펺얺줆핞슲픒줄쁢짷킫훟빦 ˖ 훊옪펆펂몒펞재컪빦뿖삲 ˖ 옪잖핞쁢-BUJO ˖ 핞쁢)BO ˖

    믎픎)BOHVM ˖ 않많빦쁢)JSBHBOB 많빦쁢,BUBLBOB
  21. 믎잚텊쁢힎핆믾 $ pip install uniscripts >>> import uniscripts >>> uniscripts.is_script('ᬊỀᤫግ໌Ẹࠃ',

    'Han') True >>> uniscripts.is_script('ᬊỀᤫግ໌Ẹࠃ', 'Hangul') False >>> uniscripts.is_script('؀ೠ޹Ҵ', 'Hangul') True
  22. 솧팒킪팒줆핞뻖찒 ˖ 헒헏픊옪퓮삖슪핂헒쭎튾핂섦빦핂쯚뻖찒몒칾쩣 ˖ " # $슿뫊맧픎줆핞쁢짦맏줆핞옪쫂몮  ˖ 많

    빦 㣓˘슿뫊맧픎줆핞쁢헒맏줆핞옪쫆삲 ˖ ˑ폏줆핞쁢짢핂 믎픎짢핂˒않쁢콚읺쁢퓮삖슪킪샎펞컮하핞
  23. &BTU"TJBO8JEUI >>> unicodedata.east_asian_width('о') 'W' >>> unicodedata.east_asian_width('A') 'Na' >>> unicodedata.east_asian_width('ᯯ') 'W'

  24. 핊삶폲쁦픎펺믾밚힎

  25. 핊삶폲쁦픎펺믾밚힎 ˖ 훊잞쭎훎찒픊빦팮펞삲웒퍊쁢뺂푷핞많잜삲 ˖ $-%3맧핂킲푷헏핆쭎쭒솒삲웦펂퍊쁢섾˘ ˖ 큲싢콚쩖픎섢퍊슽ۂۂ ˖ 핂큲싢쁢삲읆쭒핂핂펂컪훊킪졂홙픒멑맧삲