{"id":18358392,"url":"https://github.com/leonidessaguisagjr/unicodeutil","last_synced_at":"2026-02-02T18:03:45.163Z","repository":{"id":62586331,"uuid":"130645789","full_name":"leonidessaguisagjr/unicodeutil","owner":"leonidessaguisagjr","description":"Python (currently tested against Python 2.7, Python 3.6, Python 3.7, Python 3.8, Python 3.9, Python 3.10, PyPy 2.7 and PyPy 3.7) classes and functions for working with Unicode® data.  Based on v13.0.0 of the Unicode® Character Database (UCD).","archived":false,"fork":false,"pushed_at":"2023-05-22T21:54:42.000Z","size":766,"stargazers_count":2,"open_issues_count":1,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-08-29T21:45:04.633Z","etag":null,"topics":["casefold","hangul","jamo","unicode","unicode-casefold","unicode-character-database","unicode-characters","unicode-data","unicode-support"],"latest_commit_sha":null,"homepage":"https://pypi.org/project/unicodeutil/","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/leonidessaguisagjr.png","metadata":{"files":{"readme":"README.rst","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2018-04-23T05:45:18.000Z","updated_at":"2022-11-18T14:41:38.000Z","dependencies_parsed_at":"2025-04-06T13:46:15.319Z","dependency_job_id":null,"html_url":"https://github.com/leonidessaguisagjr/unicodeutil","commit_stats":null,"previous_names":[],"tags_count":3,"template":false,"template_full_name":null,"purl":"pkg:github/leonidessaguisagjr/unicodeutil","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/leonidessaguisagjr%2Funicodeutil","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/leonidessaguisagjr%2Funicodeutil/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/leonidessaguisagjr%2Funicodeutil/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/leonidessaguisagjr%2Funicodeutil/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/leonidessaguisagjr","download_url":"https://codeload.github.com/leonidessaguisagjr/unicodeutil/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/leonidessaguisagjr%2Funicodeutil/sbom","scorecard":{"id":585121,"data":{"date":"2025-08-11","repo":{"name":"github.com/leonidessaguisagjr/unicodeutil","commit":"8f233f64640e52a9f7d08b63c0b6d58e20e77787"},"scorecard":{"version":"v5.2.1-40-gf6ed084d","commit":"f6ed084d17c9236477efd66e5b258b9d4cc7b389"},"score":2.6,"checks":[{"name":"Packaging","score":-1,"reason":"packaging workflow not detected","details":["Warn: no GitHub/GitLab publishing workflow detected."],"documentation":{"short":"Determines if the project is published as a package that others can easily download, install, easily update, and uninstall.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#packaging"}},{"name":"Code-Review","score":0,"reason":"Found 0/30 approved changesets -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project requires human code review before pull requests (aka merge requests) are merged.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#code-review"}},{"name":"Token-Permissions","score":0,"reason":"detected GitHub workflow tokens with excessive permissions","details":["Warn: no topLevel permission defined: .github/workflows/python-app.yml:1","Info: no jobLevel write permissions found"],"documentation":{"short":"Determines if the project's workflows follow the principle of least privilege.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#token-permissions"}},{"name":"Maintained","score":0,"reason":"0 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project is \"actively maintained\".","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#maintained"}},{"name":"Dangerous-Workflow","score":10,"reason":"no dangerous workflow patterns detected","details":null,"documentation":{"short":"Determines if the project's GitHub Action workflows avoid dangerous patterns.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#dangerous-workflow"}},{"name":"Binary-Artifacts","score":10,"reason":"no binaries found in the repo","details":null,"documentation":{"short":"Determines if the project has generated executable (binary) artifacts in the source repository.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#binary-artifacts"}},{"name":"SAST","score":0,"reason":"no SAST tool detected","details":["Warn: no pull requests merged into dev branch"],"documentation":{"short":"Determines if the project uses static code analysis.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#sast"}},{"name":"CII-Best-Practices","score":0,"reason":"no effort to earn an OpenSSF best practices badge detected","details":null,"documentation":{"short":"Determines if the project has an OpenSSF (formerly CII) Best Practices Badge.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#cii-best-practices"}},{"name":"Security-Policy","score":0,"reason":"security policy file not detected","details":["Warn: no security policy file detected","Warn: no security file to analyze","Warn: no security file to analyze","Warn: no security file to analyze"],"documentation":{"short":"Determines if the project has published a security policy.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#security-policy"}},{"name":"Fuzzing","score":0,"reason":"project is not fuzzed","details":["Warn: no fuzzer integrations found"],"documentation":{"short":"Determines if the project uses fuzzing.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#fuzzing"}},{"name":"Pinned-Dependencies","score":0,"reason":"dependency not pinned by hash detected -- score normalized to 0","details":["Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/python-app.yml:30: update your workflow using https://app.stepsecurity.io/secureworkflow/leonidessaguisagjr/unicodeutil/python-app.yml/master?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/python-app.yml:32: update your workflow using https://app.stepsecurity.io/secureworkflow/leonidessaguisagjr/unicodeutil/python-app.yml/master?enable=pin","Warn: containerImage not pinned by hash: examples/webapp/Dockerfile:1: pin your Docker image by updating pypy:3 to pypy:3@sha256:5978ee8185b359a503faddeff09b64abb5779506be5ae2556325d8502a453448","Warn: pipCommand not pinned by hash: examples/webapp/Dockerfile:16","Warn: pipCommand not pinned by hash: .github/workflows/python-app.yml:37","Warn: pipCommand not pinned by hash: .github/workflows/python-app.yml:38","Warn: pipCommand not pinned by hash: .github/workflows/python-app.yml:39","Warn: pipCommand not pinned by hash: .github/workflows/python-app.yml:40","Info:   0 out of   2 GitHub-owned GitHubAction dependencies pinned","Info:   0 out of   1 containerImage dependencies pinned","Info:   0 out of   5 pipCommand dependencies pinned"],"documentation":{"short":"Determines if the project has declared and pinned the dependencies of its build process.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#pinned-dependencies"}},{"name":"License","score":10,"reason":"license file detected","details":["Info: project has a license file: LICENSE:0","Info: FSF or OSI recognized license: MIT License: LICENSE:0"],"documentation":{"short":"Determines if the project has defined a license.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#license"}},{"name":"Signed-Releases","score":-1,"reason":"no releases found","details":null,"documentation":{"short":"Determines if the project cryptographically signs release artifacts.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#signed-releases"}},{"name":"Branch-Protection","score":0,"reason":"branch protection not enabled on development/release branches","details":["Warn: branch protection not enabled for branch 'master'"],"documentation":{"short":"Determines if the default and release branches are protected with GitHub's branch protection settings.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#branch-protection"}},{"name":"Vulnerabilities","score":1,"reason":"9 existing vulnerabilities detected","details":["Warn: Project is vulnerable to: PYSEC-2022-43017 / GHSA-qwmp-2cf2-g9g6","Warn: Project is vulnerable to: GHSA-9hjg-9r4m-mvj7","Warn: Project is vulnerable to: GHSA-9wx4-h78v-vm56","Warn: Project is vulnerable to: PYSEC-2023-74 / GHSA-j8r2-6x86-q33q","Warn: Project is vulnerable to: PYSEC-2022-43167","Warn: Project is vulnerable to: PYSEC-2023-206","Warn: Project is vulnerable to: PYSEC-2023-62 / GHSA-m2qf-hxjv-5gpq","Warn: Project is vulnerable to: GHSA-hc5x-x2vx-497g","Warn: Project is vulnerable to: GHSA-w3h3-4rj7-4ph4"],"documentation":{"short":"Determines if the project has open, known unfixed vulnerabilities.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#vulnerabilities"}}]},"last_synced_at":"2025-08-20T20:15:13.096Z","repository_id":62586331,"created_at":"2025-08-20T20:15:13.096Z","updated_at":"2025-08-20T20:15:13.096Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":29016668,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-02-02T16:17:30.374Z","status":"ssl_error","status_checked_at":"2026-02-02T15:58:50.469Z","response_time":58,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["casefold","hangul","jamo","unicode","unicode-casefold","unicode-character-database","unicode-characters","unicode-data","unicode-support"],"created_at":"2024-11-05T22:17:43.628Z","updated_at":"2026-02-02T18:03:45.133Z","avatar_url":"https://github.com/leonidessaguisagjr.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"``unicodeutil``\n===============\n\n.. image:: https://img.shields.io/pypi/v/unicodeutil.svg\n        :target: https://pypi.python.org/pypi/unicodeutil\n\n.. image:: https://img.shields.io/github/workflow/status/leonidessaguisagjr/unicodeutil/Python%20unicodeutil\n        :target: https://github.com/leonidessaguisagjr/unicodeutil/actions/workflows/python-app.yml\n\n\n\nPython classes and functions for working with Unicode® data.  This was initially built with Python 2 in mind but has also been tested with Python 3, PyPy and PyPy3.\n\n\nDependencies\n------------\n\nThis package has the following external dependencies:\n\n* `six \u003chttps://pythonhosted.org/six/\u003e`_ - for Python 2 to 3 compatibility\n\n\nCase folding function\n---------------------\n\n``casefold(s)`` is a function for performing case folding per section 3.13 of the `Unicode® Standard \u003chttps://www.unicode.org/versions/latest/ch03.pdf\u003e`_.  Also see the `W3C page on case folding \u003chttps://www.w3.org/International/wiki/Case_folding\u003e`_ for more information on what case folding is.\n\nPython 3.3 and newer has ``str.casefold()`` already built in.  This is my attempt at building a case folding function to use with Python 2 and as such was initially only tested with Python 2.7.14.  It essentially parses the ``CaseFolding.txt`` file that is included in the `Unicode® Character Database \u003chttps://www.unicode.org/ucd/\u003e`_ to build a dictionary that is then used as a lookup table to create a copy of the input string that has been transformed to facilitate caseless comparisons.\n\nA bit more information about how I put this together on my `blog \u003chttp://www.leonidessaguisagjr.name/?p=231\u003e`_.\n\nBy default, the ``casefold(s)`` function performs full case folding.  To use simple case folding, pass the parameter ``fullcasefold=False`` (the default is ``fullcasefold=True``).  See the comments in ``CaseFolding.txt`` for an explanation of the difference between simple and full case folding.\n\nBy default, the ``casefold(s)`` function will not use the Turkic special case mappings for dotted and dotless 'i'.  To use the Turkic mapping, pass the parameter ``useturkicmapping=True`` to the function.  See the following web pages for more information on the dotted vs dotless 'i':\n\n* https://en.wikipedia.org/wiki/Dotted_and_dotless_I\n* http://www.i18nguy.com/unicode/turkish-i18n.html#problem\n\n\nExample usage\n^^^^^^^^^^^^^\n\nUsing Python 2::\n\n   \u003e\u003e\u003e from unicodeutil import casefold\n   \u003e\u003e\u003e s1 = u\"weiß\"\n   \u003e\u003e\u003e s2 = u\"WEISS\"\n   \u003e\u003e\u003e casefold(s1) == casefold(s2)\n   True\n   \u003e\u003e\u003e s1 = u\"LİMANI\"\n   \u003e\u003e\u003e s2 = u\"limanı\"\n   \u003e\u003e\u003e casefold(s1) == casefold(s2)\n   False\n   \u003e\u003e\u003e casefold(s1, useturkicmapping=True) == casefold(s2, useturkicmapping=True)\n   True\n\n\nSplitting a Python 2 string into chars, preserving surrogate pairs\n-------------------------------------------------------------------------\n\nThe ``preservesurrogates(s)`` function will split a string into a list of characters, preserving `surrogate pairs \u003chttps://www.unicode.org/glossary/#surrogate_pair\u003e`_.\n\nExample usage\n^^^^^^^^^^^^^\n\nUsing Python 2::\n\n   \u003e\u003e\u003e from unicodeutil import preservesurrogates\n   \u003e\u003e\u003e s = u\"ABC\\U0001e900DeF\\U000118a0gHıİ\"\n   \u003e\u003e\u003e list(s)\n   [u'A', u'B', u'C', u'\\ud83a', u'\\udd00', u'D', u'e', u'F', u'\\ud806', u'\\udca0', u'g', u'H', u'\\u0131', u'\\u0130']\n   \u003e\u003e\u003e for c in s:\n   ...     print c\n   ...\n   A\n   B\n   C\n   ???\n   ???\n   D\n   e\n   F\n   ???\n   ???\n   g\n   H\n   ı\n   İ\n   \u003e\u003e\u003e list(preservesurrogates(s))\n   [u'A', u'B', u'C', u'\\U0001e900', u'D', u'e', u'F', u'\\U000118a0', u'g', u'H', u'\\u0131', u'\\u0130']\n   \u003e\u003e\u003e for c in preservesurrogates(s):\n   ...     print(c)\n   ...\n   A\n   B\n   C\n   𞤀\n   D\n   e\n   F\n   𑢠\n   g\n   H\n   ı\n   İ\n\nUsing the latest Unicode® Character Database (UCD)\n--------------------------------------------------\n\nFor the Python 2.7.x line, the `unicodedata module in Python 2.7.18 \u003chttps://docs.python.org/2/library/unicodedata.html\u003e`_ is still using data from version 5.2.0 of the UCD.  Even Python 3 releases up to the 3.10.x line are also still not on the latest version of the UCD e.g. the `unicodedata module in Python 3.10.7 \u003chttps://docs.python.org/3.10/library/unicodedata.html\u003e`_ is still using data from version 13.0.0 of the UCD.  The UCD is `currently up to version 15.0.0 \u003chttps://blog.unicode.org/2022/09/announcing-unicode-standard-version-150.html\u003e`_.\n\nThe ``UnicodeCharacter`` namedtuple encapsulates the various properties associated with each Unicode® character, as explained in `Unicode Standard Annex #44, UnicodeData.txt \u003chttps://www.unicode.org/reports/tr44/#UnicodeData.txt\u003e`_.\n\nThe ``UnicodeData`` class represents the contents of the UCD as parsed from the `latest UnicodeData.txt \u003cftp://ftp.unicode.org/Public/UCD/latest/ucd/UnicodeData.txt\u003e`_ found on the Unicode Consortium FTP site.  Once an instance of the ``UnicodeData`` class has been created, it is possible to do ``dict`` style lookups using the Unicode scalar value, lookup by Unicode character by using the ``lookup_by_char(c)`` method, or lookups by name using the ``lookup_by_name(name)`` and ``lookup_by_partial_name(partial_name)`` methods.  The name lookup uses the `UAX44-LM2 \u003chttps://www.unicode.org/reports/tr44/#UAX44-LM2\u003e`_ loose matching rule when doing lookups.  Iterating through all of the data is also possible via ``items()``, ``keys()`` and ``values()`` methods.\n\nThe ``UnicodeBlocks`` class encapsulates the block information associated with a Unicode character.  Once an instance of the ``UnicodeBlocks`` class has been created, it is possible to get the Block name associated with a particular Unicode character by either doing ``dict`` style lookups using the Unicode scalar value, or using the ``lookup_by_char(c)`` method to lookup by Unicode character.  Iterating through all of the data is also possible via the ``items()``, ``keys()`` and ``values()`` methods.\n\nExample usage\n^^^^^^^^^^^^^\n\nUsing Python 2::\n\n   \u003e\u003e\u003e from unicodeutil import UnicodeBlocks, UnicodeData\n   \u003e\u003e\u003e ucd = UnicodeData()\n   \u003e\u003e\u003e ucd[0x00df]\n   UnicodeCharacter(code=u'U+00DF', name='LATIN SMALL LETTER SHARP S', category='Ll', combining=0, bidi='L', decomposition='', decimal='', digit='', numeric='', mirrored='N', unicode_1_name='', iso_comment='', uppercase='', lowercase='', titlecase='')\n   \u003e\u003e\u003e ucd[0x0130].name\n   'LATIN CAPITAL LETTER I WITH DOT ABOVE'\n   \u003e\u003e\u003e ucd.lookup_by_char(u\"ᜊ\")\n   UnicodeCharacter(code=u'U+170A', name=u'TAGALOG LETTER BA', category=u'Lo', combining=0, bidi=u'L', decomposition=u'', decimal=u'', digit=u'', numeric=u'', mirrored=u'N', unicode_1_name=u'', iso_comment=u'', uppercase=u'', lowercase=u'', titlecase=u'')\n   \u003e\u003e\u003e ucd.lookup_by_name(\"latin small letter sharp_s\")\n   UnicodeCharacter(code=u'U+00DF', name='LATIN SMALL LETTER SHARP S', category='Ll', combining=0, bidi='L', decomposition='', decimal='', digit='', numeric='', mirrored='N', unicode_1_name='', iso_comment='', uppercase='', lowercase='', titlecase='')\n   \u003e\u003e\u003e blocks = UnicodeBlocks()\n   \u003e\u003e\u003e blocks[0x00DF]\n   u'Latin-1 Supplement'\n   \u003e\u003e\u003e blocks.lookup_by_char(u\"ẞ\")\n   u'Latin Extended Additional'\n\n\nComposing and decomposing Hangul Syllables\n------------------------------------------\n\nThe function ``compose_hangul_syllable(jamo)`` takes a tuple or list of Unicode scalar values of Jamo and returns its equivalent precomposed Hangul syllable.  The complementary function ``decompose_hangul_syllable(hangul_syllable, fully_decompose=False)`` takes the Unicode scalar value of a hangul syllable and will either do a canonical decomposition (default, fully_decompose=False) or a full canonical decomposition (fully_decompose=True) of a Hangul syllable.  The return value will be a tuple of Unicode scalar values corresponding to the Jamo that the Hangul syllable has been decomposed into.  For example (taken from the `Unicode Standard, ch. 03, section 3.12, Conjoing Jamo Behavior \u003chttps://www.unicode.org/versions/latest/ch03.pdf\u003e`_)::\n\n   U+D4DB \u003c-\u003e \u003cU+D4CC, U+11B6\u003e  # Canonical Decomposition (default)\n   U+D4CC \u003c-\u003e \u003cU+1111, U+1171\u003e\n   U+D4DB \u003c-\u003e \u003cU+1111, U+1171, U+11B6\u003e  # Full Canonical Decomposition\n\nExample usage:\n^^^^^^^^^^^^^^\n\nThe following sample code snippet::\n\n   import sys\n\n   from unicodeutil import UnicodeData, compose_hangul_syllable, \\\n                           decompose_hangul_syllable\n\n   ucd = None\n\n\n   def pprint_composed(jamo):\n       hangul = compose_hangul_syllable(jamo)\n       hangul_data = ucd[hangul]\n       print(\"\u003c{0}\u003e -\u003e {1}\".format(\n           \", \".join([\" \".join([jamo_data.code, jamo_data.name])\n                      for jamo_data in [ucd[j] for j in jamo]]),\n           \" \".join([hangul_data.code, hangul_data.name])\n       ))\n\n\n   def pprint_decomposed(hangul, decomposition):\n       hangul_data = ucd[hangul]\n       print(\"{0} -\u003e \u003c{1}\u003e\".format(\n           \" \".join([hangul_data.code, hangul_data.name]),\n           \", \".join([\" \".join([jamo_data.code, jamo_data.name])\n                      for jamo_data in [ucd[jamo]\n                                        for jamo in decomposition if jamo]])\n       ))\n\n\n   def main():\n       if len(sys.argv) not in {2, 3, 4}:\n           print(\"Invalid number of arguments!\")\n           sys.exit(1)\n       global ucd\n       ucd = UnicodeData()\n       if len(sys.argv) == 2:\n           hangul = int(sys.argv[1], 16)\n           print(\"Canonical Decomposition:\")\n           pprint_decomposed(hangul,\n                             decompose_hangul_syllable(hangul,\n                                                       fully_decompose=False))\n           print(\"Full Canonical Decomposition:\")\n           pprint_decomposed(hangul,\n                             decompose_hangul_syllable(hangul,\n                                                       fully_decompose=True))\n       elif len(sys.argv) in {3, 4}:\n           print(\"Composition:\")\n           pprint_composed(tuple([int(arg, 16) for arg in sys.argv[1:]]))\n\n\n   if __name__ == \"__main__\":\n       main()\n\nWill produce the following (tested in Python 2 and Python 3)::\n\n   $ python pprint_hangul.py 0xD4DB\n   Canonical Decomposition:\n   U+D4DB HANGUL SYLLABLE PWILH -\u003e \u003cU+D4CC HANGUL SYLLABLE PWI, U+11B6 HANGUL JONGSEONG RIEUL-HIEUH\u003e\n   Full Canonical Decomposition:\n   U+D4DB HANGUL SYLLABLE PWILH -\u003e \u003cU+1111 HANGUL CHOSEONG PHIEUPH, U+1171 HANGUL JUNGSEONG WI, U+11B6 HANGUL JONGSEONG RIEUL-HIEUH\u003e\n   $ python3 pprint_hangul.py 0xD4CC 0x11B6\n   Composition:\n   \u003cU+D4CC HANGUL SYLLABLE PWI, U+11B6 HANGUL JONGSEONG RIEUL-HIEUH\u003e -\u003e U+D4DB HANGUL SYLLABLE PWILH\n   $ pypy pprint_hangul.py 0x1111 0x1171 0x11b6\n   Composition:\n   \u003cU+1111 HANGUL CHOSEONG PHIEUPH, U+1171 HANGUL JUNGSEONG WI, U+11B6 HANGUL JONGSEONG RIEUL-HIEUH\u003e -\u003e U+D4DB HANGUL SYLLABLE PWILH\n\n\nLicense\n-------\n\nThis is released under an MIT license.  See the ``LICENSE`` file in this repository for more information.\n\nThe included ``Blocks.txt``, ``CaseFolding.txt``, ``HangulSyllableType.txt``, ``Jamo.txt`` and ``UnicodeData.txt`` files are part of the Unicode® Character Database that is published by Unicode, Inc.  Please consult the `Unicode® Terms of Use \u003chttps://www.unicode.org/copyright.html\u003e`_ prior to use.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fleonidessaguisagjr%2Funicodeutil","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fleonidessaguisagjr%2Funicodeutil","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fleonidessaguisagjr%2Funicodeutil/lists"}