├── .envrc ├── .gitignore ├── .travis.yml ├── CHANGELOG.md ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── LICENSE ├── Makefile ├── README.md ├── benchmarks ├── elm.json └── src │ └── Main.elm ├── ci.sh ├── data ├── GraphemeBreakProperty.txt └── GraphemeBreakTest.txt ├── elm.json ├── flake.lock ├── flake.nix ├── script ├── generate-grapheme-break-test.py ├── generate-matcher.py ├── ucd_overlap.py └── ucd_to_json.py ├── shell.nix ├── size-benchmarks ├── elm.json ├── report.txt ├── src │ ├── WithSegmentation.elm │ └── WithoutSegmentation.elm └── stats.py ├── src └── String │ ├── Graphemes.elm │ └── Graphemes │ ├── Data.elm │ ├── Data │ ├── CR.elm │ ├── Control.elm │ ├── Extend.elm │ ├── Extended_Pictographic.elm │ ├── L.elm │ ├── LF.elm │ ├── LV.elm │ ├── LVT.elm │ ├── Prepend.elm │ ├── Regional_Indicator.elm │ ├── SpacingMark.elm │ ├── T.elm │ ├── V.elm │ └── ZWJ.elm │ ├── Parser.elm │ ├── RangeDict.elm │ └── RangeDict │ └── Range.elm └── tests ├── .dir-locals.el ├── GraphemeBreakTest.elm ├── RangeDictFuzzer.elm ├── String ├── Graphemes │ ├── DataSpec.elm │ ├── ParserSpec.elm │ └── RangeDict │ │ └── RangeSpec.elm └── GraphemesSpec.elm └── elm-verify-examples.json /.envrc: -------------------------------------------------------------------------------- 1 | use flake 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /benchmarks/*.html 2 | /benchmarks/elm-stuff 3 | /data/GraphemeBreakProperty.json 4 | /documentation.json 5 | /elm-stuff 6 | /size-benchmarks/*.gz 7 | /size-benchmarks/*.js 8 | /size-benchmarks/elm-stuff 9 | /size-benchmarks/names-in-withSegmentation.txt 10 | /size-benchmarks/names-in-withoutSegmentation.txt 11 | /size-benchmarks/new-names.txt 12 | /tests/VerifyExamples 13 | .direnv -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: nix 2 | script: ./ci.sh 3 | 4 | cache: 5 | directories: 6 | - /nix 7 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | ## 1.0.1 (July 10, 2019) 4 | 5 | updates to README to clarify common questions 6 | 7 | ## 1.0.0 (July 5, 2019) 8 | 9 | initial release, mirroring the `elm/core` `String` module 10 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Covenant Code of Conduct 2 | 3 | ## Our Pledge 4 | 5 | In the interest of fostering an open and welcoming environment, we as 6 | contributors and maintainers pledge to making participation in our project and 7 | our community a harassment-free experience for everyone, regardless of age, body 8 | size, disability, ethnicity, sex characteristics, gender identity and expression, 9 | level of experience, education, socio-economic status, nationality, personal 10 | appearance, race, religion, or sexual identity and orientation. 11 | 12 | ## Our Standards 13 | 14 | Examples of behavior that contributes to creating a positive environment 15 | include: 16 | 17 | * Using welcoming and inclusive language 18 | * Being respectful of differing viewpoints and experiences 19 | * Gracefully accepting constructive criticism 20 | * Focusing on what is best for the community 21 | * Showing empathy towards other community members 22 | 23 | Examples of unacceptable behavior by participants include: 24 | 25 | * The use of sexualized language or imagery and unwelcome sexual attention or 26 | advances 27 | * Trolling, insulting/derogatory comments, and personal or political attacks 28 | * Public or private harassment 29 | * Publishing others' private information, such as a physical or electronic 30 | address, without explicit permission 31 | * Other conduct which could reasonably be considered inappropriate in a 32 | professional setting 33 | 34 | ## Our Responsibilities 35 | 36 | Project maintainers are responsible for clarifying the standards of acceptable 37 | behavior and are expected to take appropriate and fair corrective action in 38 | response to any instances of unacceptable behavior. 39 | 40 | Project maintainers have the right and responsibility to remove, edit, or 41 | reject comments, commits, code, wiki edits, issues, and other contributions 42 | that are not aligned to this Code of Conduct, or to ban temporarily or 43 | permanently any contributor for other behaviors that they deem inappropriate, 44 | threatening, offensive, or harmful. 45 | 46 | ## Scope 47 | 48 | This Code of Conduct applies both within project spaces and in public spaces 49 | when an individual is representing the project or its community. Examples of 50 | representing a project or community include using an official project e-mail 51 | address, posting via an official social media account, or acting as an appointed 52 | representative at an online or offline event. Representation of a project may be 53 | further defined and clarified by project maintainers. 54 | 55 | ## Enforcement 56 | 57 | Instances of abusive, harassing, or otherwise unacceptable behavior may be 58 | reported by contacting the project team at brian@brianthicks.com. All 59 | complaints will be reviewed and investigated and will result in a response that 60 | is deemed necessary and appropriate to the circumstances. The project team is 61 | obligated to maintain confidentiality with regard to the reporter of an incident. 62 | Further details of specific enforcement policies may be posted separately. 63 | 64 | Project maintainers who do not follow or enforce the Code of Conduct in good 65 | faith may face temporary or permanent repercussions as determined by other 66 | members of the project's leadership. 67 | 68 | ## Attribution 69 | 70 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, 71 | available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html 72 | 73 | [homepage]: https://www.contributor-covenant.org 74 | 75 | For answers to common questions about this code of conduct, see 76 | https://www.contributor-covenant.org/faq 77 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing 2 | 3 | Thank you for considering contributing to this project! 4 | I really appreciate it! 5 | 6 | I don't want to waste your time, so I've outlined some general goals of the project and how it will grow below. 7 | That said, you might have an idea or question that's outside the scope described here! 8 | In that case, go ahead and open an issue and let's discuss. 9 | 10 | ## Goals 11 | 12 | The goal of this library is to mirror `String` from `elm/core`, but operating on graphemes instead of bytes or characters. 13 | PRs that fit with this goal are welcome! 14 | That can mean things like: 15 | 16 | - bug fixes to the parser 17 | - performance or filesize enhancements 18 | - documentation improvements 19 | - adding missing functions from `String` 20 | - upgrading to match new versions of Elm or `elm/core`. 21 | 22 | ## Non-Goals 23 | 24 | I probably will not accept PRs extending the API surface area beyond the goals above. 25 | If you need functions like you'd find in `elm-community/string-extra`, you can probably write them yourself using the public functions here! 26 | 27 | That said, I'm open to the possibility that working with graphemes might mean we need to do different things. 28 | Just open an issue before you start writing code, please, so we can discuss your use case. 29 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2019, Brian Hicks All rights reserved. 2 | 3 | Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 4 | 5 | Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 6 | 7 | Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 8 | 9 | Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. 10 | 11 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | # modules 2 | 3 | .PHONY: all 4 | all: generated 5 | 6 | .PHONY: test 7 | test: generated 8 | elm-verify-examples 9 | elm-test 10 | 11 | .PHONY: ci 12 | ci: test documentation.json 13 | test -z "$(shell git diff)" 14 | 15 | .PHONY: generated 16 | generated: $(foreach class,CR LF Control Prepend Regional_Indicator L V T LV LVT Extended_Pictographic Extend SpacingMark ZWJ,src/String/Graphemes/Data/$(class).elm) tests/GraphemeBreakTest.elm 17 | 18 | src/String/Graphemes/Data/%.elm: data/GraphemeBreakProperty.json script/generate-matcher.py 19 | @mkdir -p $(@D) 20 | python script/generate-matcher.py $@ < $< 21 | 22 | tests/GraphemeBreakTest.elm: data/GraphemeBreakTest.txt script/generate-grapheme-break-test.py 23 | python script/generate-grapheme-break-test.py $@ < $< 24 | elm-format --yes $@ 25 | 26 | documentation.json: $(find src -name '*.elm') elm.json 27 | elm make --docs $@ 28 | 29 | # data 30 | 31 | data/GraphemeBreakProperty.txt: 32 | @mkdir -p $(@D) 33 | curl https://www.unicode.org/Public/15.0.0/ucd/auxiliary/GraphemeBreakProperty.txt > $@ 34 | curl https://www.unicode.org/Public/15.0.0/ucd/emoji/emoji-data.txt >> $@ 35 | 36 | data/GraphemeBreakProperty.json: data/GraphemeBreakProperty.txt script/ucd_to_json.py 37 | @mkdir -p $(@D) 38 | python script/ucd_to_json.py < $< > $@ 39 | 40 | data/GraphemeBreakTest.txt: 41 | @mkdir -p $(@D) 42 | curl https://www.unicode.org/Public/15.0.0/ucd/auxiliary/GraphemeBreakTest.txt > $@ 43 | 44 | # benchmarks 45 | 46 | size-benchmarks/report.txt: generated $(shell find src size-benchmarks -name '*.elm') size-benchmarks/stats.py 47 | cd $(@D); ./stats.py > $(@F) 48 | 49 | size-benchmarks/names-in-%.txt: size-benchmarks/%.js size-benchmarks/report.txt 50 | grep -E '^var .+ =' $< | cut -f 2 -d ' ' | sort > $@ 51 | 52 | size-benchmarks/new-names.txt: size-benchmarks/names-in-withoutSegmentation.txt size-benchmarks/names-in-withSegmentation.txt 53 | grep -v size-benchmarks/names-in-withoutSegmentation.txt size-benchmarks/names-in-withSegmentation.txt > $@ 54 | 55 | benchmarks/benchmark.html: generated $(shell find src benchmarks -name '*.elm') 56 | cd $(@D); elm make --output=$(@F) src/Main.elm 57 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Graphemes 2 | 3 | Do string operations based on graphemes instead of codepoints or bytes. 4 | Compare: 5 | 6 | ```elm 7 | import String.Graphemes 8 | 9 | String.toList "🦸🏽‍♂️" --> [ '🦸', '🏽', '\u{200D}', '♂', '\u{FE0F}' ] 10 | 11 | String.Graphemes.toList "🦸🏽‍♂️" --> [ "🦸🏽‍♂️" ] 12 | ``` 13 | 14 | This package currently supports **Unicode 15**. 15 | 16 | ## What's going on here? Graphemes? What are those? 17 | 18 | Unicode defines a system for encoding characters as numbers. 19 | These numbers are called codepoints! 20 | For example, `a` is codepoint 97, usually written in hex like `0x0061`. 21 | There is a huge range of possible codepoints (from `0x0000` to `0x10FFFF`), although not all of these match a symbol. 22 | 23 | Codepoints are more complex than numbers, though: for a variety of reasons, a codepoint is encoded using 7 bits instead of 8. 24 | That means that we can't use regular 32-bit integers to represent them! 25 | 26 | We do this partially for historical compatibility with ASCII, and partially to save space. 27 | For example, you can encode `a` (`0x0061`) in 1 byte, but 🦸 (`0x1F9B8`) takes four. 28 | If they didn't vary in length, you would have to pad out `a` with 3 bytes worth of zeros just to support both in the same string! 29 | 30 | There's another layer of optimization, though! 31 | Imagine if you had to store a separate character for each accent mark like a, à, ā, ä, and á. 32 | You'd have a lot of characters on your hands, even before considering capital and lowercase letters! 33 | Plus, some languages use multiple accents for some characters! 34 | The combinations get ridiculous really fast, but we only have 1,114,111 (`0x10FFFF`) possible codepoints! 35 | So what we do is hardcode some combinations (like ä) for efficiency, but make separate codepoints for accents and let the software figure out how to combine them. 36 | These are called diacritic marks. 37 | So in addition to the hardcoded ä, you can put `a` and `¨` together to get the same thing. 38 | You can do this with more-or-less whatever characters and marks you want. 39 | 40 | If you get really wild, you end up with z̴̙͒ả̴̫̼̫̀̅ĺ̴̔̿͜g̷̨͇͉̊͐̚o̶̳̣̯͌̓ text! 41 | 42 | This raises another problem, though… if I have ä, I think of that as a single character, not two. 43 | But if I've encoded it as two codepoints and ask for the string length, it may tell me I have two characters! 44 | We deal with that using our final level: the grapheme. 45 | 46 | A grapheme is what you'd intuitively think of as "a character" in a writing system. 47 | Whenever you combining codepoints you're working with graphemes. 48 | This applies to diacritic marks, as we've already explained, and tons of writing systems use graphemes: Hangul, Devanagari, Thai, and Tamil among others! 49 | But it also applies to emoji! 50 | For example: 🦸🏽‍♂️ is composed of 🦸 + 🏽 + zero-width joiner (200D) + ♂ + variation selector 16 (FE0F). 51 | You tend to think of 🦸🏽‍♂️ as a single character—a very definite expression which can't really be broken up into constituent parts. 52 | That means it's a grapheme! 53 | 54 | But, final subtlety: if you used 🦸 by itself it's a grapheme too. 55 | The point is not "what codepoints are there?", it's "what is the smallest useful unit when expressing meaning?" 56 | 57 | ### So what? 58 | 59 | The above means that when we ask questions like "how long is this string?" or "what is the first character here?" we sometimes mix three levels: 60 | 61 | 1. **the byte level.** 62 | Operations like `String.length` and `String.left` operate here (or, more specifically, they operate at the UTF-16 level, which assumes that codepoints are two bytes wide.) 63 | You should probably never operate here when working with `String` in Elm. 64 | It will result in subtle bugs and corrupt data! 65 | If you know you're working at the byte level, use [`elm/bytes`](https://package.elm-lang.org/packages/elm/bytes/latest/) instead. 66 | 67 | 2. **the codepoint level.** 68 | Here, our base superhero emoji is only one character, but our skin tone and gender (🦸🏽‍♂️) take more, as discussed. 69 | This particular combination happens to be 17 *bytes* but only 5 *codepoints*. 70 | Operations like `String.foldl` operate here (so you can safely measure codepoint length with operations like `String.foldl (\_ len -> len + 1) 0 "whatever string"`.) 71 | You should operate here if you're implementing higher-level operations on the codepoints, like grapheme segmentation (hi!) or normalization. 72 | 73 | 3. **the grapheme level.** 74 | Despite being 5 codepoints, 🦸🏽‍♂ is only one grapheme️. 75 | Operations like `String.Graphemes.toList` operate here. 76 | You should operate here if you're working with unicode text in ways meaningful to a user. 77 | 78 | To underscore, if you're modifying text that the user has entered, work at the grapheme level. 79 | This reduces the possibility of errors and increases the possibility that your program will "do the right thing." 80 | 81 | Still not convinced? 82 | Here are some practical reasons you should work at the grapheme level in the browser: 83 | 84 | - If you operate at the *byte* level, you will split multi-byte characters into invalid unicode sequences. 85 | If you do the wrong thing with these sequences, you'll crash your user's browser. 86 | In fact, that's what started me writing this library! 87 | Everyone does it occasionally, but there are better ways. 88 | 89 | - If you operate at the *character* level, you will split skin tones and genders off of people emoji, split flags into country codes, and move diacritic marks around. 90 | Your user entered this text precisely in these cases, don't lose their meaning! 91 | 92 | - Think your app doesn't need those pesky diacritic marks? 93 | Think again! 94 | They're crucial to understanding in a lot of languages! 95 | For example, in Spanish, papa (potato) is different than papá (father.) 96 | Don't make your users call their dad a potato! 97 | 98 | ## Frequently Asked Questions 99 | 100 | ### What spec does this package implement? 101 | 102 | The [Grapheme Cluster Boundaries](https://unicode.org/reports/tr29/#Grapheme_Cluster_Boundaries) section of [UAX #29](https://unicode.org/reports/tr29/). 103 | 104 | ### Does this package correctly reverse strings with diacritics? 105 | 106 | Yes! 107 | It reverses the order of the graphemes, not the codepoints. 108 | This means that it does not move diacritics around and emoji are perfectly safe. 109 | 110 | ```elm 111 | import String.Graphemes 112 | 113 | -- äo without normalization 114 | String.Graphemes.reverse "a\u{0308}o" --> "oa\u{0308}" 115 | 116 | -- compare with String 117 | String.reverse "a\u{0308}o" --> "o\u{0308}a" 118 | ``` 119 | 120 | ### Does this package do normalization? 121 | 122 | No, and it probably never will. 123 | It's a [whole 'nother spec](https://unicode.org/reports/tr15/#Norm_Forms) in the Unicode standard which doesn't really fit in this package. 124 | 125 | That said, it *looks* like you could implement it in a similar way as the internal `String.Graphemes.Parser`, so give it a go in a new package of your own! 126 | 127 | (n.b. normalization in this case means turning `"a\u{0308}"` into `"ä"`, usually for the purposes of improving equality checks.) 128 | 129 | ### Does this package segment words or sentences? 130 | 131 | No, and it probably never will. 132 | Segmenting words and sentences is locale- and implementation-dependent, so it's really hard to address them in a general way. 133 | Rather than introducing confusion ("it *should* segment here… why doesn't it?") we only segment graphemes. 134 | 135 | That said, word and sentence segmentation rely on grapheme segmentation, so you're on the right track by asking this! 136 | [UAX #29](https://unicode.org/reports/tr29/) has guidance here. 137 | 138 | ### Why not "fix" `elm/core`'s `String` instead of writing a new package? 139 | 140 | The `String` module solves a different—but overlapping—set of problems. 141 | For example, you do not always want to work with graphemes: sometimes you need to be able to decompose into codepoints or operate at the byte level. 142 | As usual, it's all tradeoffs. 143 | 144 | That said, if it eventually becomes obvious that merging into core would be a good thing we may do that. 145 | In that case, we would probably just keep equivalents of `String.Graphemes.uncons` and `String.Graphemes.foldl`. 146 | Everything else is implemented in terms of those two operations. 147 | 148 | ### Why a drop-in replacement? / Why does the code refer to `String` functions so much? 149 | 150 | Unless you've worked with unicode strings a lot, it can be tricky to know which level (bytes, codepoints, or graphemes) you're operating at with any given time. 151 | So instead of giving you the functions you *might* need, and leaving you to implement the rest on your own, we provide all of them and only change the ones where you'd run into trouble. 152 | 153 | But not *all* of the functions in `String` need to be modified. 154 | In those cases, we just pass through to the `String` functions! 155 | 156 | This way, you don't have to worry about it. 157 | You could potentially do `import String.Graphemes as String` in a module, fix the type errors, and all of a sudden all your string operations work with graphemes. 158 | 159 | ## Climate Action 160 | 161 | I want my open-source activities to support projects addressing the climate crisis (for example, projects in clean energy, public transit, reforestation, or sustainable agriculture.) 162 | If you are working on such a project, and find a bug or missing feature in any of my libraries, **please let me know and I will treat your issue as high priority.** 163 | I'd also be happy to support such projects in other ways. 164 | In particular, I've worked with Elm for a long time and would be happy to advise on your implementation. 165 | 166 | ## License 167 | 168 | This code in this project is licensed under the BSD 3-Clause license, located at LICENSE in the source. 169 | 170 | The documentation strings in `String.Graphemes` are derived from those in `elm/core`'s `String`, © 2019 Evan Czaplicki, and licensed under the BSD 3-Clause license. 171 | 172 | The grapheme break property data used here are © 2019 Unicode®, Inc., and licensed under their [terms of use](http://www.unicode.org/terms_of_use.html). 173 | -------------------------------------------------------------------------------- /benchmarks/elm.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "application", 3 | "source-directories": [ 4 | "src", 5 | "../src" 6 | ], 7 | "elm-version": "0.19.0", 8 | "dependencies": { 9 | "direct": { 10 | "elm/browser": "1.0.1", 11 | "elm/core": "1.0.2", 12 | "elm/html": "1.0.0", 13 | "elm-explorations/benchmark": "1.0.1" 14 | }, 15 | "indirect": { 16 | "BrianHicks/elm-trend": "2.1.2", 17 | "Skinney/murmur3": "2.0.8", 18 | "elm/json": "1.1.3", 19 | "elm/regex": "1.0.0", 20 | "elm/time": "1.0.0", 21 | "elm/url": "1.0.0", 22 | "elm/virtual-dom": "1.0.2", 23 | "mdgriffith/style-elements": "5.0.1" 24 | } 25 | }, 26 | "test-dependencies": { 27 | "direct": {}, 28 | "indirect": {} 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /benchmarks/src/Main.elm: -------------------------------------------------------------------------------- 1 | module Main exposing (main) 2 | 3 | import Benchmark exposing (..) 4 | import Benchmark.Runner exposing (BenchmarkProgram, program) 5 | import String.Graphemes as Graphemes 6 | 7 | 8 | main : BenchmarkProgram 9 | main = 10 | program <| 11 | Benchmark.describe "unicode segmentation" 12 | [ Benchmark.compare "plain text" 13 | "characters" 14 | (\_ -> String.toList "123456") 15 | "graphemes" 16 | (\_ -> Graphemes.toList "123456") 17 | , Benchmark.compare "emoji" 18 | "characters" 19 | (\_ -> String.toList "\u{1F9B8}\u{1F3FD}\u{200D}♂️") 20 | "graphemes" 21 | (\_ -> Graphemes.toList "\u{1F9B8}\u{1F3FD}\u{200D}♂️") 22 | ] 23 | -------------------------------------------------------------------------------- /ci.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | nix-shell --pure --run 'make ci' 3 | -------------------------------------------------------------------------------- /data/GraphemeBreakTest.txt: -------------------------------------------------------------------------------- 1 | # GraphemeBreakTest-15.0.0.txt 2 | # Date: 2022-02-26, 00:38:37 GMT 3 | # © 2022 Unicode®, Inc. 4 | # Unicode and the Unicode Logo are registered trademarks of Unicode, Inc. in the U.S. and other countries. 5 | # For terms of use, see https://www.unicode.org/terms_of_use.html 6 | # 7 | # Unicode Character Database 8 | # For documentation, see https://www.unicode.org/reports/tr44/ 9 | # 10 | # Default Grapheme_Cluster_Break Test 11 | # 12 | # Format: 13 | # (# )? 14 | # contains hex Unicode code points, with 15 | # ÷ wherever there is a break opportunity, and 16 | # × wherever there is not. 17 | # the format can change, but currently it shows: 18 | # - the sample character name 19 | # - (x) the Grapheme_Cluster_Break property value for the sample character 20 | # - [x] the rule that determines whether there is a break or not, 21 | # as listed in the Rules section of GraphemeBreakTest.html 22 | # 23 | # These samples may be extended or changed in the future. 24 | # 25 | ÷ 0020 ÷ 0020 ÷ # ÷ [0.2] SPACE (Other) ÷ [999.0] SPACE (Other) ÷ [0.3] 26 | ÷ 0020 × 0308 ÷ 0020 ÷ # ÷ [0.2] SPACE (Other) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] SPACE (Other) ÷ [0.3] 27 | ÷ 0020 ÷ 000D ÷ # ÷ [0.2] SPACE (Other) ÷ [5.0] (CR) ÷ [0.3] 28 | ÷ 0020 × 0308 ÷ 000D ÷ # ÷ [0.2] SPACE (Other) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (CR) ÷ [0.3] 29 | ÷ 0020 ÷ 000A ÷ # ÷ [0.2] SPACE (Other) ÷ [5.0] (LF) ÷ [0.3] 30 | ÷ 0020 × 0308 ÷ 000A ÷ # ÷ [0.2] SPACE (Other) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (LF) ÷ [0.3] 31 | ÷ 0020 ÷ 0001 ÷ # ÷ [0.2] SPACE (Other) ÷ [5.0] (Control) ÷ [0.3] 32 | ÷ 0020 × 0308 ÷ 0001 ÷ # ÷ [0.2] SPACE (Other) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (Control) ÷ [0.3] 33 | ÷ 0020 × 034F ÷ # ÷ [0.2] SPACE (Other) × [9.0] COMBINING GRAPHEME JOINER (Extend) ÷ [0.3] 34 | ÷ 0020 × 0308 × 034F ÷ # ÷ [0.2] SPACE (Other) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] COMBINING GRAPHEME JOINER (Extend) ÷ [0.3] 35 | ÷ 0020 ÷ 1F1E6 ÷ # ÷ [0.2] SPACE (Other) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] 36 | ÷ 0020 × 0308 ÷ 1F1E6 ÷ # ÷ [0.2] SPACE (Other) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] 37 | ÷ 0020 ÷ 0600 ÷ # ÷ [0.2] SPACE (Other) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3] 38 | ÷ 0020 × 0308 ÷ 0600 ÷ # ÷ [0.2] SPACE (Other) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3] 39 | ÷ 0020 × 0903 ÷ # ÷ [0.2] SPACE (Other) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [0.3] 40 | ÷ 0020 × 0308 × 0903 ÷ # ÷ [0.2] SPACE (Other) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [0.3] 41 | ÷ 0020 ÷ 1100 ÷ # ÷ [0.2] SPACE (Other) ÷ [999.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3] 42 | ÷ 0020 × 0308 ÷ 1100 ÷ # ÷ [0.2] SPACE (Other) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3] 43 | ÷ 0020 ÷ 1160 ÷ # ÷ [0.2] SPACE (Other) ÷ [999.0] HANGUL JUNGSEONG FILLER (V) ÷ [0.3] 44 | ÷ 0020 × 0308 ÷ 1160 ÷ # ÷ [0.2] SPACE (Other) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL JUNGSEONG FILLER (V) ÷ [0.3] 45 | ÷ 0020 ÷ 11A8 ÷ # ÷ [0.2] SPACE (Other) ÷ [999.0] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3] 46 | ÷ 0020 × 0308 ÷ 11A8 ÷ # ÷ [0.2] SPACE (Other) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3] 47 | ÷ 0020 ÷ AC00 ÷ # ÷ [0.2] SPACE (Other) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3] 48 | ÷ 0020 × 0308 ÷ AC00 ÷ # ÷ [0.2] SPACE (Other) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3] 49 | ÷ 0020 ÷ AC01 ÷ # ÷ [0.2] SPACE (Other) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3] 50 | ÷ 0020 × 0308 ÷ AC01 ÷ # ÷ [0.2] SPACE (Other) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3] 51 | ÷ 0020 ÷ 231A ÷ # ÷ [0.2] SPACE (Other) ÷ [999.0] WATCH (ExtPict) ÷ [0.3] 52 | ÷ 0020 × 0308 ÷ 231A ÷ # ÷ [0.2] SPACE (Other) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] WATCH (ExtPict) ÷ [0.3] 53 | ÷ 0020 × 0300 ÷ # ÷ [0.2] SPACE (Other) × [9.0] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [0.3] 54 | ÷ 0020 × 0308 × 0300 ÷ # ÷ [0.2] SPACE (Other) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [0.3] 55 | ÷ 0020 × 200D ÷ # ÷ [0.2] SPACE (Other) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [0.3] 56 | ÷ 0020 × 0308 × 200D ÷ # ÷ [0.2] SPACE (Other) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [0.3] 57 | ÷ 0020 ÷ 0378 ÷ # ÷ [0.2] SPACE (Other) ÷ [999.0] (Other) ÷ [0.3] 58 | ÷ 0020 × 0308 ÷ 0378 ÷ # ÷ [0.2] SPACE (Other) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] (Other) ÷ [0.3] 59 | ÷ 000D ÷ 0020 ÷ # ÷ [0.2] (CR) ÷ [4.0] SPACE (Other) ÷ [0.3] 60 | ÷ 000D ÷ 0308 ÷ 0020 ÷ # ÷ [0.2] (CR) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] SPACE (Other) ÷ [0.3] 61 | ÷ 000D ÷ 000D ÷ # ÷ [0.2] (CR) ÷ [4.0] (CR) ÷ [0.3] 62 | ÷ 000D ÷ 0308 ÷ 000D ÷ # ÷ [0.2] (CR) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (CR) ÷ [0.3] 63 | ÷ 000D × 000A ÷ # ÷ [0.2] (CR) × [3.0] (LF) ÷ [0.3] 64 | ÷ 000D ÷ 0308 ÷ 000A ÷ # ÷ [0.2] (CR) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (LF) ÷ [0.3] 65 | ÷ 000D ÷ 0001 ÷ # ÷ [0.2] (CR) ÷ [4.0] (Control) ÷ [0.3] 66 | ÷ 000D ÷ 0308 ÷ 0001 ÷ # ÷ [0.2] (CR) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (Control) ÷ [0.3] 67 | ÷ 000D ÷ 034F ÷ # ÷ [0.2] (CR) ÷ [4.0] COMBINING GRAPHEME JOINER (Extend) ÷ [0.3] 68 | ÷ 000D ÷ 0308 × 034F ÷ # ÷ [0.2] (CR) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] COMBINING GRAPHEME JOINER (Extend) ÷ [0.3] 69 | ÷ 000D ÷ 1F1E6 ÷ # ÷ [0.2] (CR) ÷ [4.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] 70 | ÷ 000D ÷ 0308 ÷ 1F1E6 ÷ # ÷ [0.2] (CR) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] 71 | ÷ 000D ÷ 0600 ÷ # ÷ [0.2] (CR) ÷ [4.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3] 72 | ÷ 000D ÷ 0308 ÷ 0600 ÷ # ÷ [0.2] (CR) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3] 73 | ÷ 000D ÷ 0903 ÷ # ÷ [0.2] (CR) ÷ [4.0] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [0.3] 74 | ÷ 000D ÷ 0308 × 0903 ÷ # ÷ [0.2] (CR) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [0.3] 75 | ÷ 000D ÷ 1100 ÷ # ÷ [0.2] (CR) ÷ [4.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3] 76 | ÷ 000D ÷ 0308 ÷ 1100 ÷ # ÷ [0.2] (CR) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3] 77 | ÷ 000D ÷ 1160 ÷ # ÷ [0.2] (CR) ÷ [4.0] HANGUL JUNGSEONG FILLER (V) ÷ [0.3] 78 | ÷ 000D ÷ 0308 ÷ 1160 ÷ # ÷ [0.2] (CR) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL JUNGSEONG FILLER (V) ÷ [0.3] 79 | ÷ 000D ÷ 11A8 ÷ # ÷ [0.2] (CR) ÷ [4.0] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3] 80 | ÷ 000D ÷ 0308 ÷ 11A8 ÷ # ÷ [0.2] (CR) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3] 81 | ÷ 000D ÷ AC00 ÷ # ÷ [0.2] (CR) ÷ [4.0] HANGUL SYLLABLE GA (LV) ÷ [0.3] 82 | ÷ 000D ÷ 0308 ÷ AC00 ÷ # ÷ [0.2] (CR) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3] 83 | ÷ 000D ÷ AC01 ÷ # ÷ [0.2] (CR) ÷ [4.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3] 84 | ÷ 000D ÷ 0308 ÷ AC01 ÷ # ÷ [0.2] (CR) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3] 85 | ÷ 000D ÷ 231A ÷ # ÷ [0.2] (CR) ÷ [4.0] WATCH (ExtPict) ÷ [0.3] 86 | ÷ 000D ÷ 0308 ÷ 231A ÷ # ÷ [0.2] (CR) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] WATCH (ExtPict) ÷ [0.3] 87 | ÷ 000D ÷ 0300 ÷ # ÷ [0.2] (CR) ÷ [4.0] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [0.3] 88 | ÷ 000D ÷ 0308 × 0300 ÷ # ÷ [0.2] (CR) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [0.3] 89 | ÷ 000D ÷ 200D ÷ # ÷ [0.2] (CR) ÷ [4.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [0.3] 90 | ÷ 000D ÷ 0308 × 200D ÷ # ÷ [0.2] (CR) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [0.3] 91 | ÷ 000D ÷ 0378 ÷ # ÷ [0.2] (CR) ÷ [4.0] (Other) ÷ [0.3] 92 | ÷ 000D ÷ 0308 ÷ 0378 ÷ # ÷ [0.2] (CR) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] (Other) ÷ [0.3] 93 | ÷ 000A ÷ 0020 ÷ # ÷ [0.2] (LF) ÷ [4.0] SPACE (Other) ÷ [0.3] 94 | ÷ 000A ÷ 0308 ÷ 0020 ÷ # ÷ [0.2] (LF) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] SPACE (Other) ÷ [0.3] 95 | ÷ 000A ÷ 000D ÷ # ÷ [0.2] (LF) ÷ [4.0] (CR) ÷ [0.3] 96 | ÷ 000A ÷ 0308 ÷ 000D ÷ # ÷ [0.2] (LF) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (CR) ÷ [0.3] 97 | ÷ 000A ÷ 000A ÷ # ÷ [0.2] (LF) ÷ [4.0] (LF) ÷ [0.3] 98 | ÷ 000A ÷ 0308 ÷ 000A ÷ # ÷ [0.2] (LF) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (LF) ÷ [0.3] 99 | ÷ 000A ÷ 0001 ÷ # ÷ [0.2] (LF) ÷ [4.0] (Control) ÷ [0.3] 100 | ÷ 000A ÷ 0308 ÷ 0001 ÷ # ÷ [0.2] (LF) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (Control) ÷ [0.3] 101 | ÷ 000A ÷ 034F ÷ # ÷ [0.2] (LF) ÷ [4.0] COMBINING GRAPHEME JOINER (Extend) ÷ [0.3] 102 | ÷ 000A ÷ 0308 × 034F ÷ # ÷ [0.2] (LF) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] COMBINING GRAPHEME JOINER (Extend) ÷ [0.3] 103 | ÷ 000A ÷ 1F1E6 ÷ # ÷ [0.2] (LF) ÷ [4.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] 104 | ÷ 000A ÷ 0308 ÷ 1F1E6 ÷ # ÷ [0.2] (LF) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] 105 | ÷ 000A ÷ 0600 ÷ # ÷ [0.2] (LF) ÷ [4.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3] 106 | ÷ 000A ÷ 0308 ÷ 0600 ÷ # ÷ [0.2] (LF) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3] 107 | ÷ 000A ÷ 0903 ÷ # ÷ [0.2] (LF) ÷ [4.0] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [0.3] 108 | ÷ 000A ÷ 0308 × 0903 ÷ # ÷ [0.2] (LF) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [0.3] 109 | ÷ 000A ÷ 1100 ÷ # ÷ [0.2] (LF) ÷ [4.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3] 110 | ÷ 000A ÷ 0308 ÷ 1100 ÷ # ÷ [0.2] (LF) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3] 111 | ÷ 000A ÷ 1160 ÷ # ÷ [0.2] (LF) ÷ [4.0] HANGUL JUNGSEONG FILLER (V) ÷ [0.3] 112 | ÷ 000A ÷ 0308 ÷ 1160 ÷ # ÷ [0.2] (LF) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL JUNGSEONG FILLER (V) ÷ [0.3] 113 | ÷ 000A ÷ 11A8 ÷ # ÷ [0.2] (LF) ÷ [4.0] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3] 114 | ÷ 000A ÷ 0308 ÷ 11A8 ÷ # ÷ [0.2] (LF) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3] 115 | ÷ 000A ÷ AC00 ÷ # ÷ [0.2] (LF) ÷ [4.0] HANGUL SYLLABLE GA (LV) ÷ [0.3] 116 | ÷ 000A ÷ 0308 ÷ AC00 ÷ # ÷ [0.2] (LF) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3] 117 | ÷ 000A ÷ AC01 ÷ # ÷ [0.2] (LF) ÷ [4.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3] 118 | ÷ 000A ÷ 0308 ÷ AC01 ÷ # ÷ [0.2] (LF) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3] 119 | ÷ 000A ÷ 231A ÷ # ÷ [0.2] (LF) ÷ [4.0] WATCH (ExtPict) ÷ [0.3] 120 | ÷ 000A ÷ 0308 ÷ 231A ÷ # ÷ [0.2] (LF) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] WATCH (ExtPict) ÷ [0.3] 121 | ÷ 000A ÷ 0300 ÷ # ÷ [0.2] (LF) ÷ [4.0] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [0.3] 122 | ÷ 000A ÷ 0308 × 0300 ÷ # ÷ [0.2] (LF) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [0.3] 123 | ÷ 000A ÷ 200D ÷ # ÷ [0.2] (LF) ÷ [4.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [0.3] 124 | ÷ 000A ÷ 0308 × 200D ÷ # ÷ [0.2] (LF) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [0.3] 125 | ÷ 000A ÷ 0378 ÷ # ÷ [0.2] (LF) ÷ [4.0] (Other) ÷ [0.3] 126 | ÷ 000A ÷ 0308 ÷ 0378 ÷ # ÷ [0.2] (LF) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] (Other) ÷ [0.3] 127 | ÷ 0001 ÷ 0020 ÷ # ÷ [0.2] (Control) ÷ [4.0] SPACE (Other) ÷ [0.3] 128 | ÷ 0001 ÷ 0308 ÷ 0020 ÷ # ÷ [0.2] (Control) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] SPACE (Other) ÷ [0.3] 129 | ÷ 0001 ÷ 000D ÷ # ÷ [0.2] (Control) ÷ [4.0] (CR) ÷ [0.3] 130 | ÷ 0001 ÷ 0308 ÷ 000D ÷ # ÷ [0.2] (Control) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (CR) ÷ [0.3] 131 | ÷ 0001 ÷ 000A ÷ # ÷ [0.2] (Control) ÷ [4.0] (LF) ÷ [0.3] 132 | ÷ 0001 ÷ 0308 ÷ 000A ÷ # ÷ [0.2] (Control) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (LF) ÷ [0.3] 133 | ÷ 0001 ÷ 0001 ÷ # ÷ [0.2] (Control) ÷ [4.0] (Control) ÷ [0.3] 134 | ÷ 0001 ÷ 0308 ÷ 0001 ÷ # ÷ [0.2] (Control) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (Control) ÷ [0.3] 135 | ÷ 0001 ÷ 034F ÷ # ÷ [0.2] (Control) ÷ [4.0] COMBINING GRAPHEME JOINER (Extend) ÷ [0.3] 136 | ÷ 0001 ÷ 0308 × 034F ÷ # ÷ [0.2] (Control) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] COMBINING GRAPHEME JOINER (Extend) ÷ [0.3] 137 | ÷ 0001 ÷ 1F1E6 ÷ # ÷ [0.2] (Control) ÷ [4.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] 138 | ÷ 0001 ÷ 0308 ÷ 1F1E6 ÷ # ÷ [0.2] (Control) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] 139 | ÷ 0001 ÷ 0600 ÷ # ÷ [0.2] (Control) ÷ [4.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3] 140 | ÷ 0001 ÷ 0308 ÷ 0600 ÷ # ÷ [0.2] (Control) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3] 141 | ÷ 0001 ÷ 0903 ÷ # ÷ [0.2] (Control) ÷ [4.0] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [0.3] 142 | ÷ 0001 ÷ 0308 × 0903 ÷ # ÷ [0.2] (Control) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [0.3] 143 | ÷ 0001 ÷ 1100 ÷ # ÷ [0.2] (Control) ÷ [4.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3] 144 | ÷ 0001 ÷ 0308 ÷ 1100 ÷ # ÷ [0.2] (Control) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3] 145 | ÷ 0001 ÷ 1160 ÷ # ÷ [0.2] (Control) ÷ [4.0] HANGUL JUNGSEONG FILLER (V) ÷ [0.3] 146 | ÷ 0001 ÷ 0308 ÷ 1160 ÷ # ÷ [0.2] (Control) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL JUNGSEONG FILLER (V) ÷ [0.3] 147 | ÷ 0001 ÷ 11A8 ÷ # ÷ [0.2] (Control) ÷ [4.0] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3] 148 | ÷ 0001 ÷ 0308 ÷ 11A8 ÷ # ÷ [0.2] (Control) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3] 149 | ÷ 0001 ÷ AC00 ÷ # ÷ [0.2] (Control) ÷ [4.0] HANGUL SYLLABLE GA (LV) ÷ [0.3] 150 | ÷ 0001 ÷ 0308 ÷ AC00 ÷ # ÷ [0.2] (Control) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3] 151 | ÷ 0001 ÷ AC01 ÷ # ÷ [0.2] (Control) ÷ [4.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3] 152 | ÷ 0001 ÷ 0308 ÷ AC01 ÷ # ÷ [0.2] (Control) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3] 153 | ÷ 0001 ÷ 231A ÷ # ÷ [0.2] (Control) ÷ [4.0] WATCH (ExtPict) ÷ [0.3] 154 | ÷ 0001 ÷ 0308 ÷ 231A ÷ # ÷ [0.2] (Control) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] WATCH (ExtPict) ÷ [0.3] 155 | ÷ 0001 ÷ 0300 ÷ # ÷ [0.2] (Control) ÷ [4.0] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [0.3] 156 | ÷ 0001 ÷ 0308 × 0300 ÷ # ÷ [0.2] (Control) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [0.3] 157 | ÷ 0001 ÷ 200D ÷ # ÷ [0.2] (Control) ÷ [4.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [0.3] 158 | ÷ 0001 ÷ 0308 × 200D ÷ # ÷ [0.2] (Control) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [0.3] 159 | ÷ 0001 ÷ 0378 ÷ # ÷ [0.2] (Control) ÷ [4.0] (Other) ÷ [0.3] 160 | ÷ 0001 ÷ 0308 ÷ 0378 ÷ # ÷ [0.2] (Control) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] (Other) ÷ [0.3] 161 | ÷ 034F ÷ 0020 ÷ # ÷ [0.2] COMBINING GRAPHEME JOINER (Extend) ÷ [999.0] SPACE (Other) ÷ [0.3] 162 | ÷ 034F × 0308 ÷ 0020 ÷ # ÷ [0.2] COMBINING GRAPHEME JOINER (Extend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] SPACE (Other) ÷ [0.3] 163 | ÷ 034F ÷ 000D ÷ # ÷ [0.2] COMBINING GRAPHEME JOINER (Extend) ÷ [5.0] (CR) ÷ [0.3] 164 | ÷ 034F × 0308 ÷ 000D ÷ # ÷ [0.2] COMBINING GRAPHEME JOINER (Extend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (CR) ÷ [0.3] 165 | ÷ 034F ÷ 000A ÷ # ÷ [0.2] COMBINING GRAPHEME JOINER (Extend) ÷ [5.0] (LF) ÷ [0.3] 166 | ÷ 034F × 0308 ÷ 000A ÷ # ÷ [0.2] COMBINING GRAPHEME JOINER (Extend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (LF) ÷ [0.3] 167 | ÷ 034F ÷ 0001 ÷ # ÷ [0.2] COMBINING GRAPHEME JOINER (Extend) ÷ [5.0] (Control) ÷ [0.3] 168 | ÷ 034F × 0308 ÷ 0001 ÷ # ÷ [0.2] COMBINING GRAPHEME JOINER (Extend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (Control) ÷ [0.3] 169 | ÷ 034F × 034F ÷ # ÷ [0.2] COMBINING GRAPHEME JOINER (Extend) × [9.0] COMBINING GRAPHEME JOINER (Extend) ÷ [0.3] 170 | ÷ 034F × 0308 × 034F ÷ # ÷ [0.2] COMBINING GRAPHEME JOINER (Extend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] COMBINING GRAPHEME JOINER (Extend) ÷ [0.3] 171 | ÷ 034F ÷ 1F1E6 ÷ # ÷ [0.2] COMBINING GRAPHEME JOINER (Extend) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] 172 | ÷ 034F × 0308 ÷ 1F1E6 ÷ # ÷ [0.2] COMBINING GRAPHEME JOINER (Extend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] 173 | ÷ 034F ÷ 0600 ÷ # ÷ [0.2] COMBINING GRAPHEME JOINER (Extend) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3] 174 | ÷ 034F × 0308 ÷ 0600 ÷ # ÷ [0.2] COMBINING GRAPHEME JOINER (Extend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3] 175 | ÷ 034F × 0903 ÷ # ÷ [0.2] COMBINING GRAPHEME JOINER (Extend) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [0.3] 176 | ÷ 034F × 0308 × 0903 ÷ # ÷ [0.2] COMBINING GRAPHEME JOINER (Extend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [0.3] 177 | ÷ 034F ÷ 1100 ÷ # ÷ [0.2] COMBINING GRAPHEME JOINER (Extend) ÷ [999.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3] 178 | ÷ 034F × 0308 ÷ 1100 ÷ # ÷ [0.2] COMBINING GRAPHEME JOINER (Extend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3] 179 | ÷ 034F ÷ 1160 ÷ # ÷ [0.2] COMBINING GRAPHEME JOINER (Extend) ÷ [999.0] HANGUL JUNGSEONG FILLER (V) ÷ [0.3] 180 | ÷ 034F × 0308 ÷ 1160 ÷ # ÷ [0.2] COMBINING GRAPHEME JOINER (Extend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL JUNGSEONG FILLER (V) ÷ [0.3] 181 | ÷ 034F ÷ 11A8 ÷ # ÷ [0.2] COMBINING GRAPHEME JOINER (Extend) ÷ [999.0] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3] 182 | ÷ 034F × 0308 ÷ 11A8 ÷ # ÷ [0.2] COMBINING GRAPHEME JOINER (Extend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3] 183 | ÷ 034F ÷ AC00 ÷ # ÷ [0.2] COMBINING GRAPHEME JOINER (Extend) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3] 184 | ÷ 034F × 0308 ÷ AC00 ÷ # ÷ [0.2] COMBINING GRAPHEME JOINER (Extend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3] 185 | ÷ 034F ÷ AC01 ÷ # ÷ [0.2] COMBINING GRAPHEME JOINER (Extend) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3] 186 | ÷ 034F × 0308 ÷ AC01 ÷ # ÷ [0.2] COMBINING GRAPHEME JOINER (Extend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3] 187 | ÷ 034F ÷ 231A ÷ # ÷ [0.2] COMBINING GRAPHEME JOINER (Extend) ÷ [999.0] WATCH (ExtPict) ÷ [0.3] 188 | ÷ 034F × 0308 ÷ 231A ÷ # ÷ [0.2] COMBINING GRAPHEME JOINER (Extend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] WATCH (ExtPict) ÷ [0.3] 189 | ÷ 034F × 0300 ÷ # ÷ [0.2] COMBINING GRAPHEME JOINER (Extend) × [9.0] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [0.3] 190 | ÷ 034F × 0308 × 0300 ÷ # ÷ [0.2] COMBINING GRAPHEME JOINER (Extend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [0.3] 191 | ÷ 034F × 200D ÷ # ÷ [0.2] COMBINING GRAPHEME JOINER (Extend) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [0.3] 192 | ÷ 034F × 0308 × 200D ÷ # ÷ [0.2] COMBINING GRAPHEME JOINER (Extend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [0.3] 193 | ÷ 034F ÷ 0378 ÷ # ÷ [0.2] COMBINING GRAPHEME JOINER (Extend) ÷ [999.0] (Other) ÷ [0.3] 194 | ÷ 034F × 0308 ÷ 0378 ÷ # ÷ [0.2] COMBINING GRAPHEME JOINER (Extend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] (Other) ÷ [0.3] 195 | ÷ 1F1E6 ÷ 0020 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [999.0] SPACE (Other) ÷ [0.3] 196 | ÷ 1F1E6 × 0308 ÷ 0020 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] SPACE (Other) ÷ [0.3] 197 | ÷ 1F1E6 ÷ 000D ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [5.0] (CR) ÷ [0.3] 198 | ÷ 1F1E6 × 0308 ÷ 000D ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (CR) ÷ [0.3] 199 | ÷ 1F1E6 ÷ 000A ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [5.0] (LF) ÷ [0.3] 200 | ÷ 1F1E6 × 0308 ÷ 000A ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (LF) ÷ [0.3] 201 | ÷ 1F1E6 ÷ 0001 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [5.0] (Control) ÷ [0.3] 202 | ÷ 1F1E6 × 0308 ÷ 0001 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (Control) ÷ [0.3] 203 | ÷ 1F1E6 × 034F ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING GRAPHEME JOINER (Extend) ÷ [0.3] 204 | ÷ 1F1E6 × 0308 × 034F ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] COMBINING GRAPHEME JOINER (Extend) ÷ [0.3] 205 | ÷ 1F1E6 × 1F1E6 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [12.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] 206 | ÷ 1F1E6 × 0308 ÷ 1F1E6 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] 207 | ÷ 1F1E6 ÷ 0600 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3] 208 | ÷ 1F1E6 × 0308 ÷ 0600 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3] 209 | ÷ 1F1E6 × 0903 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [0.3] 210 | ÷ 1F1E6 × 0308 × 0903 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [0.3] 211 | ÷ 1F1E6 ÷ 1100 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [999.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3] 212 | ÷ 1F1E6 × 0308 ÷ 1100 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3] 213 | ÷ 1F1E6 ÷ 1160 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [999.0] HANGUL JUNGSEONG FILLER (V) ÷ [0.3] 214 | ÷ 1F1E6 × 0308 ÷ 1160 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL JUNGSEONG FILLER (V) ÷ [0.3] 215 | ÷ 1F1E6 ÷ 11A8 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [999.0] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3] 216 | ÷ 1F1E6 × 0308 ÷ 11A8 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3] 217 | ÷ 1F1E6 ÷ AC00 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3] 218 | ÷ 1F1E6 × 0308 ÷ AC00 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3] 219 | ÷ 1F1E6 ÷ AC01 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3] 220 | ÷ 1F1E6 × 0308 ÷ AC01 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3] 221 | ÷ 1F1E6 ÷ 231A ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [999.0] WATCH (ExtPict) ÷ [0.3] 222 | ÷ 1F1E6 × 0308 ÷ 231A ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] WATCH (ExtPict) ÷ [0.3] 223 | ÷ 1F1E6 × 0300 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [0.3] 224 | ÷ 1F1E6 × 0308 × 0300 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [0.3] 225 | ÷ 1F1E6 × 200D ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [0.3] 226 | ÷ 1F1E6 × 0308 × 200D ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [0.3] 227 | ÷ 1F1E6 ÷ 0378 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [999.0] (Other) ÷ [0.3] 228 | ÷ 1F1E6 × 0308 ÷ 0378 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] (Other) ÷ [0.3] 229 | ÷ 0600 × 0020 ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.2] SPACE (Other) ÷ [0.3] 230 | ÷ 0600 × 0308 ÷ 0020 ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] SPACE (Other) ÷ [0.3] 231 | ÷ 0600 ÷ 000D ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) ÷ [5.0] (CR) ÷ [0.3] 232 | ÷ 0600 × 0308 ÷ 000D ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (CR) ÷ [0.3] 233 | ÷ 0600 ÷ 000A ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) ÷ [5.0] (LF) ÷ [0.3] 234 | ÷ 0600 × 0308 ÷ 000A ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (LF) ÷ [0.3] 235 | ÷ 0600 ÷ 0001 ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) ÷ [5.0] (Control) ÷ [0.3] 236 | ÷ 0600 × 0308 ÷ 0001 ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (Control) ÷ [0.3] 237 | ÷ 0600 × 034F ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.0] COMBINING GRAPHEME JOINER (Extend) ÷ [0.3] 238 | ÷ 0600 × 0308 × 034F ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] COMBINING GRAPHEME JOINER (Extend) ÷ [0.3] 239 | ÷ 0600 × 1F1E6 ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] 240 | ÷ 0600 × 0308 ÷ 1F1E6 ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] 241 | ÷ 0600 × 0600 ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.2] ARABIC NUMBER SIGN (Prepend) ÷ [0.3] 242 | ÷ 0600 × 0308 ÷ 0600 ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3] 243 | ÷ 0600 × 0903 ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [0.3] 244 | ÷ 0600 × 0308 × 0903 ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [0.3] 245 | ÷ 0600 × 1100 ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.2] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3] 246 | ÷ 0600 × 0308 ÷ 1100 ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3] 247 | ÷ 0600 × 1160 ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.2] HANGUL JUNGSEONG FILLER (V) ÷ [0.3] 248 | ÷ 0600 × 0308 ÷ 1160 ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL JUNGSEONG FILLER (V) ÷ [0.3] 249 | ÷ 0600 × 11A8 ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.2] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3] 250 | ÷ 0600 × 0308 ÷ 11A8 ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3] 251 | ÷ 0600 × AC00 ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.2] HANGUL SYLLABLE GA (LV) ÷ [0.3] 252 | ÷ 0600 × 0308 ÷ AC00 ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3] 253 | ÷ 0600 × AC01 ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.2] HANGUL SYLLABLE GAG (LVT) ÷ [0.3] 254 | ÷ 0600 × 0308 ÷ AC01 ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3] 255 | ÷ 0600 × 231A ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.2] WATCH (ExtPict) ÷ [0.3] 256 | ÷ 0600 × 0308 ÷ 231A ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] WATCH (ExtPict) ÷ [0.3] 257 | ÷ 0600 × 0300 ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.0] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [0.3] 258 | ÷ 0600 × 0308 × 0300 ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [0.3] 259 | ÷ 0600 × 200D ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [0.3] 260 | ÷ 0600 × 0308 × 200D ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [0.3] 261 | ÷ 0600 × 0378 ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.2] (Other) ÷ [0.3] 262 | ÷ 0600 × 0308 ÷ 0378 ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] (Other) ÷ [0.3] 263 | ÷ 0903 ÷ 0020 ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [999.0] SPACE (Other) ÷ [0.3] 264 | ÷ 0903 × 0308 ÷ 0020 ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] SPACE (Other) ÷ [0.3] 265 | ÷ 0903 ÷ 000D ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [5.0] (CR) ÷ [0.3] 266 | ÷ 0903 × 0308 ÷ 000D ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (CR) ÷ [0.3] 267 | ÷ 0903 ÷ 000A ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [5.0] (LF) ÷ [0.3] 268 | ÷ 0903 × 0308 ÷ 000A ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (LF) ÷ [0.3] 269 | ÷ 0903 ÷ 0001 ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [5.0] (Control) ÷ [0.3] 270 | ÷ 0903 × 0308 ÷ 0001 ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (Control) ÷ [0.3] 271 | ÷ 0903 × 034F ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark) × [9.0] COMBINING GRAPHEME JOINER (Extend) ÷ [0.3] 272 | ÷ 0903 × 0308 × 034F ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] COMBINING GRAPHEME JOINER (Extend) ÷ [0.3] 273 | ÷ 0903 ÷ 1F1E6 ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] 274 | ÷ 0903 × 0308 ÷ 1F1E6 ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] 275 | ÷ 0903 ÷ 0600 ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3] 276 | ÷ 0903 × 0308 ÷ 0600 ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3] 277 | ÷ 0903 × 0903 ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [0.3] 278 | ÷ 0903 × 0308 × 0903 ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [0.3] 279 | ÷ 0903 ÷ 1100 ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [999.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3] 280 | ÷ 0903 × 0308 ÷ 1100 ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3] 281 | ÷ 0903 ÷ 1160 ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [999.0] HANGUL JUNGSEONG FILLER (V) ÷ [0.3] 282 | ÷ 0903 × 0308 ÷ 1160 ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL JUNGSEONG FILLER (V) ÷ [0.3] 283 | ÷ 0903 ÷ 11A8 ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [999.0] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3] 284 | ÷ 0903 × 0308 ÷ 11A8 ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3] 285 | ÷ 0903 ÷ AC00 ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3] 286 | ÷ 0903 × 0308 ÷ AC00 ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3] 287 | ÷ 0903 ÷ AC01 ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3] 288 | ÷ 0903 × 0308 ÷ AC01 ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3] 289 | ÷ 0903 ÷ 231A ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [999.0] WATCH (ExtPict) ÷ [0.3] 290 | ÷ 0903 × 0308 ÷ 231A ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] WATCH (ExtPict) ÷ [0.3] 291 | ÷ 0903 × 0300 ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark) × [9.0] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [0.3] 292 | ÷ 0903 × 0308 × 0300 ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [0.3] 293 | ÷ 0903 × 200D ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [0.3] 294 | ÷ 0903 × 0308 × 200D ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [0.3] 295 | ÷ 0903 ÷ 0378 ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [999.0] (Other) ÷ [0.3] 296 | ÷ 0903 × 0308 ÷ 0378 ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] (Other) ÷ [0.3] 297 | ÷ 1100 ÷ 0020 ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) ÷ [999.0] SPACE (Other) ÷ [0.3] 298 | ÷ 1100 × 0308 ÷ 0020 ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] SPACE (Other) ÷ [0.3] 299 | ÷ 1100 ÷ 000D ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) ÷ [5.0] (CR) ÷ [0.3] 300 | ÷ 1100 × 0308 ÷ 000D ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (CR) ÷ [0.3] 301 | ÷ 1100 ÷ 000A ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) ÷ [5.0] (LF) ÷ [0.3] 302 | ÷ 1100 × 0308 ÷ 000A ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (LF) ÷ [0.3] 303 | ÷ 1100 ÷ 0001 ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) ÷ [5.0] (Control) ÷ [0.3] 304 | ÷ 1100 × 0308 ÷ 0001 ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (Control) ÷ [0.3] 305 | ÷ 1100 × 034F ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) × [9.0] COMBINING GRAPHEME JOINER (Extend) ÷ [0.3] 306 | ÷ 1100 × 0308 × 034F ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] COMBINING GRAPHEME JOINER (Extend) ÷ [0.3] 307 | ÷ 1100 ÷ 1F1E6 ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] 308 | ÷ 1100 × 0308 ÷ 1F1E6 ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] 309 | ÷ 1100 ÷ 0600 ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3] 310 | ÷ 1100 × 0308 ÷ 0600 ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3] 311 | ÷ 1100 × 0903 ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [0.3] 312 | ÷ 1100 × 0308 × 0903 ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [0.3] 313 | ÷ 1100 × 1100 ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) × [6.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3] 314 | ÷ 1100 × 0308 ÷ 1100 ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3] 315 | ÷ 1100 × 1160 ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) × [6.0] HANGUL JUNGSEONG FILLER (V) ÷ [0.3] 316 | ÷ 1100 × 0308 ÷ 1160 ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL JUNGSEONG FILLER (V) ÷ [0.3] 317 | ÷ 1100 ÷ 11A8 ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) ÷ [999.0] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3] 318 | ÷ 1100 × 0308 ÷ 11A8 ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3] 319 | ÷ 1100 × AC00 ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) × [6.0] HANGUL SYLLABLE GA (LV) ÷ [0.3] 320 | ÷ 1100 × 0308 ÷ AC00 ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3] 321 | ÷ 1100 × AC01 ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) × [6.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3] 322 | ÷ 1100 × 0308 ÷ AC01 ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3] 323 | ÷ 1100 ÷ 231A ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) ÷ [999.0] WATCH (ExtPict) ÷ [0.3] 324 | ÷ 1100 × 0308 ÷ 231A ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] WATCH (ExtPict) ÷ [0.3] 325 | ÷ 1100 × 0300 ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) × [9.0] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [0.3] 326 | ÷ 1100 × 0308 × 0300 ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [0.3] 327 | ÷ 1100 × 200D ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [0.3] 328 | ÷ 1100 × 0308 × 200D ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [0.3] 329 | ÷ 1100 ÷ 0378 ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) ÷ [999.0] (Other) ÷ [0.3] 330 | ÷ 1100 × 0308 ÷ 0378 ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] (Other) ÷ [0.3] 331 | ÷ 1160 ÷ 0020 ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) ÷ [999.0] SPACE (Other) ÷ [0.3] 332 | ÷ 1160 × 0308 ÷ 0020 ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] SPACE (Other) ÷ [0.3] 333 | ÷ 1160 ÷ 000D ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) ÷ [5.0] (CR) ÷ [0.3] 334 | ÷ 1160 × 0308 ÷ 000D ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (CR) ÷ [0.3] 335 | ÷ 1160 ÷ 000A ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) ÷ [5.0] (LF) ÷ [0.3] 336 | ÷ 1160 × 0308 ÷ 000A ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (LF) ÷ [0.3] 337 | ÷ 1160 ÷ 0001 ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) ÷ [5.0] (Control) ÷ [0.3] 338 | ÷ 1160 × 0308 ÷ 0001 ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (Control) ÷ [0.3] 339 | ÷ 1160 × 034F ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) × [9.0] COMBINING GRAPHEME JOINER (Extend) ÷ [0.3] 340 | ÷ 1160 × 0308 × 034F ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] COMBINING GRAPHEME JOINER (Extend) ÷ [0.3] 341 | ÷ 1160 ÷ 1F1E6 ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] 342 | ÷ 1160 × 0308 ÷ 1F1E6 ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] 343 | ÷ 1160 ÷ 0600 ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3] 344 | ÷ 1160 × 0308 ÷ 0600 ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3] 345 | ÷ 1160 × 0903 ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [0.3] 346 | ÷ 1160 × 0308 × 0903 ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [0.3] 347 | ÷ 1160 ÷ 1100 ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) ÷ [999.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3] 348 | ÷ 1160 × 0308 ÷ 1100 ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3] 349 | ÷ 1160 × 1160 ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) × [7.0] HANGUL JUNGSEONG FILLER (V) ÷ [0.3] 350 | ÷ 1160 × 0308 ÷ 1160 ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL JUNGSEONG FILLER (V) ÷ [0.3] 351 | ÷ 1160 × 11A8 ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) × [7.0] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3] 352 | ÷ 1160 × 0308 ÷ 11A8 ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3] 353 | ÷ 1160 ÷ AC00 ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3] 354 | ÷ 1160 × 0308 ÷ AC00 ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3] 355 | ÷ 1160 ÷ AC01 ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3] 356 | ÷ 1160 × 0308 ÷ AC01 ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3] 357 | ÷ 1160 ÷ 231A ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) ÷ [999.0] WATCH (ExtPict) ÷ [0.3] 358 | ÷ 1160 × 0308 ÷ 231A ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] WATCH (ExtPict) ÷ [0.3] 359 | ÷ 1160 × 0300 ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) × [9.0] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [0.3] 360 | ÷ 1160 × 0308 × 0300 ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [0.3] 361 | ÷ 1160 × 200D ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [0.3] 362 | ÷ 1160 × 0308 × 200D ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [0.3] 363 | ÷ 1160 ÷ 0378 ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) ÷ [999.0] (Other) ÷ [0.3] 364 | ÷ 1160 × 0308 ÷ 0378 ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] (Other) ÷ [0.3] 365 | ÷ 11A8 ÷ 0020 ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) ÷ [999.0] SPACE (Other) ÷ [0.3] 366 | ÷ 11A8 × 0308 ÷ 0020 ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] SPACE (Other) ÷ [0.3] 367 | ÷ 11A8 ÷ 000D ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) ÷ [5.0] (CR) ÷ [0.3] 368 | ÷ 11A8 × 0308 ÷ 000D ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (CR) ÷ [0.3] 369 | ÷ 11A8 ÷ 000A ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) ÷ [5.0] (LF) ÷ [0.3] 370 | ÷ 11A8 × 0308 ÷ 000A ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (LF) ÷ [0.3] 371 | ÷ 11A8 ÷ 0001 ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) ÷ [5.0] (Control) ÷ [0.3] 372 | ÷ 11A8 × 0308 ÷ 0001 ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (Control) ÷ [0.3] 373 | ÷ 11A8 × 034F ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) × [9.0] COMBINING GRAPHEME JOINER (Extend) ÷ [0.3] 374 | ÷ 11A8 × 0308 × 034F ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] COMBINING GRAPHEME JOINER (Extend) ÷ [0.3] 375 | ÷ 11A8 ÷ 1F1E6 ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] 376 | ÷ 11A8 × 0308 ÷ 1F1E6 ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] 377 | ÷ 11A8 ÷ 0600 ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3] 378 | ÷ 11A8 × 0308 ÷ 0600 ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3] 379 | ÷ 11A8 × 0903 ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [0.3] 380 | ÷ 11A8 × 0308 × 0903 ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [0.3] 381 | ÷ 11A8 ÷ 1100 ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) ÷ [999.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3] 382 | ÷ 11A8 × 0308 ÷ 1100 ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3] 383 | ÷ 11A8 ÷ 1160 ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) ÷ [999.0] HANGUL JUNGSEONG FILLER (V) ÷ [0.3] 384 | ÷ 11A8 × 0308 ÷ 1160 ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL JUNGSEONG FILLER (V) ÷ [0.3] 385 | ÷ 11A8 × 11A8 ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) × [8.0] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3] 386 | ÷ 11A8 × 0308 ÷ 11A8 ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3] 387 | ÷ 11A8 ÷ AC00 ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3] 388 | ÷ 11A8 × 0308 ÷ AC00 ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3] 389 | ÷ 11A8 ÷ AC01 ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3] 390 | ÷ 11A8 × 0308 ÷ AC01 ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3] 391 | ÷ 11A8 ÷ 231A ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) ÷ [999.0] WATCH (ExtPict) ÷ [0.3] 392 | ÷ 11A8 × 0308 ÷ 231A ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] WATCH (ExtPict) ÷ [0.3] 393 | ÷ 11A8 × 0300 ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) × [9.0] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [0.3] 394 | ÷ 11A8 × 0308 × 0300 ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [0.3] 395 | ÷ 11A8 × 200D ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [0.3] 396 | ÷ 11A8 × 0308 × 200D ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [0.3] 397 | ÷ 11A8 ÷ 0378 ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) ÷ [999.0] (Other) ÷ [0.3] 398 | ÷ 11A8 × 0308 ÷ 0378 ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] (Other) ÷ [0.3] 399 | ÷ AC00 ÷ 0020 ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) ÷ [999.0] SPACE (Other) ÷ [0.3] 400 | ÷ AC00 × 0308 ÷ 0020 ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] SPACE (Other) ÷ [0.3] 401 | ÷ AC00 ÷ 000D ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) ÷ [5.0] (CR) ÷ [0.3] 402 | ÷ AC00 × 0308 ÷ 000D ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (CR) ÷ [0.3] 403 | ÷ AC00 ÷ 000A ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) ÷ [5.0] (LF) ÷ [0.3] 404 | ÷ AC00 × 0308 ÷ 000A ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (LF) ÷ [0.3] 405 | ÷ AC00 ÷ 0001 ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) ÷ [5.0] (Control) ÷ [0.3] 406 | ÷ AC00 × 0308 ÷ 0001 ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (Control) ÷ [0.3] 407 | ÷ AC00 × 034F ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) × [9.0] COMBINING GRAPHEME JOINER (Extend) ÷ [0.3] 408 | ÷ AC00 × 0308 × 034F ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] COMBINING GRAPHEME JOINER (Extend) ÷ [0.3] 409 | ÷ AC00 ÷ 1F1E6 ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] 410 | ÷ AC00 × 0308 ÷ 1F1E6 ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] 411 | ÷ AC00 ÷ 0600 ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3] 412 | ÷ AC00 × 0308 ÷ 0600 ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3] 413 | ÷ AC00 × 0903 ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [0.3] 414 | ÷ AC00 × 0308 × 0903 ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [0.3] 415 | ÷ AC00 ÷ 1100 ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) ÷ [999.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3] 416 | ÷ AC00 × 0308 ÷ 1100 ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3] 417 | ÷ AC00 × 1160 ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) × [7.0] HANGUL JUNGSEONG FILLER (V) ÷ [0.3] 418 | ÷ AC00 × 0308 ÷ 1160 ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL JUNGSEONG FILLER (V) ÷ [0.3] 419 | ÷ AC00 × 11A8 ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) × [7.0] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3] 420 | ÷ AC00 × 0308 ÷ 11A8 ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3] 421 | ÷ AC00 ÷ AC00 ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3] 422 | ÷ AC00 × 0308 ÷ AC00 ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3] 423 | ÷ AC00 ÷ AC01 ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3] 424 | ÷ AC00 × 0308 ÷ AC01 ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3] 425 | ÷ AC00 ÷ 231A ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) ÷ [999.0] WATCH (ExtPict) ÷ [0.3] 426 | ÷ AC00 × 0308 ÷ 231A ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] WATCH (ExtPict) ÷ [0.3] 427 | ÷ AC00 × 0300 ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) × [9.0] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [0.3] 428 | ÷ AC00 × 0308 × 0300 ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [0.3] 429 | ÷ AC00 × 200D ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [0.3] 430 | ÷ AC00 × 0308 × 200D ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [0.3] 431 | ÷ AC00 ÷ 0378 ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) ÷ [999.0] (Other) ÷ [0.3] 432 | ÷ AC00 × 0308 ÷ 0378 ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] (Other) ÷ [0.3] 433 | ÷ AC01 ÷ 0020 ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) ÷ [999.0] SPACE (Other) ÷ [0.3] 434 | ÷ AC01 × 0308 ÷ 0020 ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] SPACE (Other) ÷ [0.3] 435 | ÷ AC01 ÷ 000D ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) ÷ [5.0] (CR) ÷ [0.3] 436 | ÷ AC01 × 0308 ÷ 000D ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (CR) ÷ [0.3] 437 | ÷ AC01 ÷ 000A ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) ÷ [5.0] (LF) ÷ [0.3] 438 | ÷ AC01 × 0308 ÷ 000A ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (LF) ÷ [0.3] 439 | ÷ AC01 ÷ 0001 ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) ÷ [5.0] (Control) ÷ [0.3] 440 | ÷ AC01 × 0308 ÷ 0001 ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (Control) ÷ [0.3] 441 | ÷ AC01 × 034F ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) × [9.0] COMBINING GRAPHEME JOINER (Extend) ÷ [0.3] 442 | ÷ AC01 × 0308 × 034F ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] COMBINING GRAPHEME JOINER (Extend) ÷ [0.3] 443 | ÷ AC01 ÷ 1F1E6 ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] 444 | ÷ AC01 × 0308 ÷ 1F1E6 ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] 445 | ÷ AC01 ÷ 0600 ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3] 446 | ÷ AC01 × 0308 ÷ 0600 ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3] 447 | ÷ AC01 × 0903 ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [0.3] 448 | ÷ AC01 × 0308 × 0903 ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [0.3] 449 | ÷ AC01 ÷ 1100 ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) ÷ [999.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3] 450 | ÷ AC01 × 0308 ÷ 1100 ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3] 451 | ÷ AC01 ÷ 1160 ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) ÷ [999.0] HANGUL JUNGSEONG FILLER (V) ÷ [0.3] 452 | ÷ AC01 × 0308 ÷ 1160 ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL JUNGSEONG FILLER (V) ÷ [0.3] 453 | ÷ AC01 × 11A8 ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) × [8.0] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3] 454 | ÷ AC01 × 0308 ÷ 11A8 ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3] 455 | ÷ AC01 ÷ AC00 ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3] 456 | ÷ AC01 × 0308 ÷ AC00 ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3] 457 | ÷ AC01 ÷ AC01 ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3] 458 | ÷ AC01 × 0308 ÷ AC01 ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3] 459 | ÷ AC01 ÷ 231A ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) ÷ [999.0] WATCH (ExtPict) ÷ [0.3] 460 | ÷ AC01 × 0308 ÷ 231A ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] WATCH (ExtPict) ÷ [0.3] 461 | ÷ AC01 × 0300 ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) × [9.0] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [0.3] 462 | ÷ AC01 × 0308 × 0300 ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [0.3] 463 | ÷ AC01 × 200D ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [0.3] 464 | ÷ AC01 × 0308 × 200D ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [0.3] 465 | ÷ AC01 ÷ 0378 ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) ÷ [999.0] (Other) ÷ [0.3] 466 | ÷ AC01 × 0308 ÷ 0378 ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] (Other) ÷ [0.3] 467 | ÷ 231A ÷ 0020 ÷ # ÷ [0.2] WATCH (ExtPict) ÷ [999.0] SPACE (Other) ÷ [0.3] 468 | ÷ 231A × 0308 ÷ 0020 ÷ # ÷ [0.2] WATCH (ExtPict) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] SPACE (Other) ÷ [0.3] 469 | ÷ 231A ÷ 000D ÷ # ÷ [0.2] WATCH (ExtPict) ÷ [5.0] (CR) ÷ [0.3] 470 | ÷ 231A × 0308 ÷ 000D ÷ # ÷ [0.2] WATCH (ExtPict) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (CR) ÷ [0.3] 471 | ÷ 231A ÷ 000A ÷ # ÷ [0.2] WATCH (ExtPict) ÷ [5.0] (LF) ÷ [0.3] 472 | ÷ 231A × 0308 ÷ 000A ÷ # ÷ [0.2] WATCH (ExtPict) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (LF) ÷ [0.3] 473 | ÷ 231A ÷ 0001 ÷ # ÷ [0.2] WATCH (ExtPict) ÷ [5.0] (Control) ÷ [0.3] 474 | ÷ 231A × 0308 ÷ 0001 ÷ # ÷ [0.2] WATCH (ExtPict) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (Control) ÷ [0.3] 475 | ÷ 231A × 034F ÷ # ÷ [0.2] WATCH (ExtPict) × [9.0] COMBINING GRAPHEME JOINER (Extend) ÷ [0.3] 476 | ÷ 231A × 0308 × 034F ÷ # ÷ [0.2] WATCH (ExtPict) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] COMBINING GRAPHEME JOINER (Extend) ÷ [0.3] 477 | ÷ 231A ÷ 1F1E6 ÷ # ÷ [0.2] WATCH (ExtPict) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] 478 | ÷ 231A × 0308 ÷ 1F1E6 ÷ # ÷ [0.2] WATCH (ExtPict) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] 479 | ÷ 231A ÷ 0600 ÷ # ÷ [0.2] WATCH (ExtPict) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3] 480 | ÷ 231A × 0308 ÷ 0600 ÷ # ÷ [0.2] WATCH (ExtPict) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3] 481 | ÷ 231A × 0903 ÷ # ÷ [0.2] WATCH (ExtPict) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [0.3] 482 | ÷ 231A × 0308 × 0903 ÷ # ÷ [0.2] WATCH (ExtPict) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [0.3] 483 | ÷ 231A ÷ 1100 ÷ # ÷ [0.2] WATCH (ExtPict) ÷ [999.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3] 484 | ÷ 231A × 0308 ÷ 1100 ÷ # ÷ [0.2] WATCH (ExtPict) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3] 485 | ÷ 231A ÷ 1160 ÷ # ÷ [0.2] WATCH (ExtPict) ÷ [999.0] HANGUL JUNGSEONG FILLER (V) ÷ [0.3] 486 | ÷ 231A × 0308 ÷ 1160 ÷ # ÷ [0.2] WATCH (ExtPict) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL JUNGSEONG FILLER (V) ÷ [0.3] 487 | ÷ 231A ÷ 11A8 ÷ # ÷ [0.2] WATCH (ExtPict) ÷ [999.0] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3] 488 | ÷ 231A × 0308 ÷ 11A8 ÷ # ÷ [0.2] WATCH (ExtPict) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3] 489 | ÷ 231A ÷ AC00 ÷ # ÷ [0.2] WATCH (ExtPict) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3] 490 | ÷ 231A × 0308 ÷ AC00 ÷ # ÷ [0.2] WATCH (ExtPict) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3] 491 | ÷ 231A ÷ AC01 ÷ # ÷ [0.2] WATCH (ExtPict) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3] 492 | ÷ 231A × 0308 ÷ AC01 ÷ # ÷ [0.2] WATCH (ExtPict) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3] 493 | ÷ 231A ÷ 231A ÷ # ÷ [0.2] WATCH (ExtPict) ÷ [999.0] WATCH (ExtPict) ÷ [0.3] 494 | ÷ 231A × 0308 ÷ 231A ÷ # ÷ [0.2] WATCH (ExtPict) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] WATCH (ExtPict) ÷ [0.3] 495 | ÷ 231A × 0300 ÷ # ÷ [0.2] WATCH (ExtPict) × [9.0] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [0.3] 496 | ÷ 231A × 0308 × 0300 ÷ # ÷ [0.2] WATCH (ExtPict) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [0.3] 497 | ÷ 231A × 200D ÷ # ÷ [0.2] WATCH (ExtPict) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [0.3] 498 | ÷ 231A × 0308 × 200D ÷ # ÷ [0.2] WATCH (ExtPict) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [0.3] 499 | ÷ 231A ÷ 0378 ÷ # ÷ [0.2] WATCH (ExtPict) ÷ [999.0] (Other) ÷ [0.3] 500 | ÷ 231A × 0308 ÷ 0378 ÷ # ÷ [0.2] WATCH (ExtPict) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] (Other) ÷ [0.3] 501 | ÷ 0300 ÷ 0020 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [999.0] SPACE (Other) ÷ [0.3] 502 | ÷ 0300 × 0308 ÷ 0020 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] SPACE (Other) ÷ [0.3] 503 | ÷ 0300 ÷ 000D ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [5.0] (CR) ÷ [0.3] 504 | ÷ 0300 × 0308 ÷ 000D ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (CR) ÷ [0.3] 505 | ÷ 0300 ÷ 000A ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [5.0] (LF) ÷ [0.3] 506 | ÷ 0300 × 0308 ÷ 000A ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (LF) ÷ [0.3] 507 | ÷ 0300 ÷ 0001 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [5.0] (Control) ÷ [0.3] 508 | ÷ 0300 × 0308 ÷ 0001 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (Control) ÷ [0.3] 509 | ÷ 0300 × 034F ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) × [9.0] COMBINING GRAPHEME JOINER (Extend) ÷ [0.3] 510 | ÷ 0300 × 0308 × 034F ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] COMBINING GRAPHEME JOINER (Extend) ÷ [0.3] 511 | ÷ 0300 ÷ 1F1E6 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] 512 | ÷ 0300 × 0308 ÷ 1F1E6 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] 513 | ÷ 0300 ÷ 0600 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3] 514 | ÷ 0300 × 0308 ÷ 0600 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3] 515 | ÷ 0300 × 0903 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [0.3] 516 | ÷ 0300 × 0308 × 0903 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [0.3] 517 | ÷ 0300 ÷ 1100 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [999.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3] 518 | ÷ 0300 × 0308 ÷ 1100 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3] 519 | ÷ 0300 ÷ 1160 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [999.0] HANGUL JUNGSEONG FILLER (V) ÷ [0.3] 520 | ÷ 0300 × 0308 ÷ 1160 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL JUNGSEONG FILLER (V) ÷ [0.3] 521 | ÷ 0300 ÷ 11A8 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [999.0] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3] 522 | ÷ 0300 × 0308 ÷ 11A8 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3] 523 | ÷ 0300 ÷ AC00 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3] 524 | ÷ 0300 × 0308 ÷ AC00 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3] 525 | ÷ 0300 ÷ AC01 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3] 526 | ÷ 0300 × 0308 ÷ AC01 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3] 527 | ÷ 0300 ÷ 231A ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [999.0] WATCH (ExtPict) ÷ [0.3] 528 | ÷ 0300 × 0308 ÷ 231A ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] WATCH (ExtPict) ÷ [0.3] 529 | ÷ 0300 × 0300 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) × [9.0] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [0.3] 530 | ÷ 0300 × 0308 × 0300 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [0.3] 531 | ÷ 0300 × 200D ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [0.3] 532 | ÷ 0300 × 0308 × 200D ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [0.3] 533 | ÷ 0300 ÷ 0378 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [999.0] (Other) ÷ [0.3] 534 | ÷ 0300 × 0308 ÷ 0378 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] (Other) ÷ [0.3] 535 | ÷ 200D ÷ 0020 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [999.0] SPACE (Other) ÷ [0.3] 536 | ÷ 200D × 0308 ÷ 0020 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] SPACE (Other) ÷ [0.3] 537 | ÷ 200D ÷ 000D ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [5.0] (CR) ÷ [0.3] 538 | ÷ 200D × 0308 ÷ 000D ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (CR) ÷ [0.3] 539 | ÷ 200D ÷ 000A ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [5.0] (LF) ÷ [0.3] 540 | ÷ 200D × 0308 ÷ 000A ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (LF) ÷ [0.3] 541 | ÷ 200D ÷ 0001 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [5.0] (Control) ÷ [0.3] 542 | ÷ 200D × 0308 ÷ 0001 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (Control) ÷ [0.3] 543 | ÷ 200D × 034F ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) × [9.0] COMBINING GRAPHEME JOINER (Extend) ÷ [0.3] 544 | ÷ 200D × 0308 × 034F ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] COMBINING GRAPHEME JOINER (Extend) ÷ [0.3] 545 | ÷ 200D ÷ 1F1E6 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] 546 | ÷ 200D × 0308 ÷ 1F1E6 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] 547 | ÷ 200D ÷ 0600 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3] 548 | ÷ 200D × 0308 ÷ 0600 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3] 549 | ÷ 200D × 0903 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [0.3] 550 | ÷ 200D × 0308 × 0903 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [0.3] 551 | ÷ 200D ÷ 1100 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [999.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3] 552 | ÷ 200D × 0308 ÷ 1100 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3] 553 | ÷ 200D ÷ 1160 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [999.0] HANGUL JUNGSEONG FILLER (V) ÷ [0.3] 554 | ÷ 200D × 0308 ÷ 1160 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL JUNGSEONG FILLER (V) ÷ [0.3] 555 | ÷ 200D ÷ 11A8 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [999.0] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3] 556 | ÷ 200D × 0308 ÷ 11A8 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3] 557 | ÷ 200D ÷ AC00 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3] 558 | ÷ 200D × 0308 ÷ AC00 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3] 559 | ÷ 200D ÷ AC01 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3] 560 | ÷ 200D × 0308 ÷ AC01 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3] 561 | ÷ 200D ÷ 231A ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [999.0] WATCH (ExtPict) ÷ [0.3] 562 | ÷ 200D × 0308 ÷ 231A ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] WATCH (ExtPict) ÷ [0.3] 563 | ÷ 200D × 0300 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) × [9.0] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [0.3] 564 | ÷ 200D × 0308 × 0300 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [0.3] 565 | ÷ 200D × 200D ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [0.3] 566 | ÷ 200D × 0308 × 200D ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [0.3] 567 | ÷ 200D ÷ 0378 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [999.0] (Other) ÷ [0.3] 568 | ÷ 200D × 0308 ÷ 0378 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] (Other) ÷ [0.3] 569 | ÷ 0378 ÷ 0020 ÷ # ÷ [0.2] (Other) ÷ [999.0] SPACE (Other) ÷ [0.3] 570 | ÷ 0378 × 0308 ÷ 0020 ÷ # ÷ [0.2] (Other) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] SPACE (Other) ÷ [0.3] 571 | ÷ 0378 ÷ 000D ÷ # ÷ [0.2] (Other) ÷ [5.0] (CR) ÷ [0.3] 572 | ÷ 0378 × 0308 ÷ 000D ÷ # ÷ [0.2] (Other) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (CR) ÷ [0.3] 573 | ÷ 0378 ÷ 000A ÷ # ÷ [0.2] (Other) ÷ [5.0] (LF) ÷ [0.3] 574 | ÷ 0378 × 0308 ÷ 000A ÷ # ÷ [0.2] (Other) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (LF) ÷ [0.3] 575 | ÷ 0378 ÷ 0001 ÷ # ÷ [0.2] (Other) ÷ [5.0] (Control) ÷ [0.3] 576 | ÷ 0378 × 0308 ÷ 0001 ÷ # ÷ [0.2] (Other) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (Control) ÷ [0.3] 577 | ÷ 0378 × 034F ÷ # ÷ [0.2] (Other) × [9.0] COMBINING GRAPHEME JOINER (Extend) ÷ [0.3] 578 | ÷ 0378 × 0308 × 034F ÷ # ÷ [0.2] (Other) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] COMBINING GRAPHEME JOINER (Extend) ÷ [0.3] 579 | ÷ 0378 ÷ 1F1E6 ÷ # ÷ [0.2] (Other) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] 580 | ÷ 0378 × 0308 ÷ 1F1E6 ÷ # ÷ [0.2] (Other) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] 581 | ÷ 0378 ÷ 0600 ÷ # ÷ [0.2] (Other) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3] 582 | ÷ 0378 × 0308 ÷ 0600 ÷ # ÷ [0.2] (Other) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3] 583 | ÷ 0378 × 0903 ÷ # ÷ [0.2] (Other) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [0.3] 584 | ÷ 0378 × 0308 × 0903 ÷ # ÷ [0.2] (Other) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [0.3] 585 | ÷ 0378 ÷ 1100 ÷ # ÷ [0.2] (Other) ÷ [999.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3] 586 | ÷ 0378 × 0308 ÷ 1100 ÷ # ÷ [0.2] (Other) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3] 587 | ÷ 0378 ÷ 1160 ÷ # ÷ [0.2] (Other) ÷ [999.0] HANGUL JUNGSEONG FILLER (V) ÷ [0.3] 588 | ÷ 0378 × 0308 ÷ 1160 ÷ # ÷ [0.2] (Other) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL JUNGSEONG FILLER (V) ÷ [0.3] 589 | ÷ 0378 ÷ 11A8 ÷ # ÷ [0.2] (Other) ÷ [999.0] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3] 590 | ÷ 0378 × 0308 ÷ 11A8 ÷ # ÷ [0.2] (Other) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3] 591 | ÷ 0378 ÷ AC00 ÷ # ÷ [0.2] (Other) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3] 592 | ÷ 0378 × 0308 ÷ AC00 ÷ # ÷ [0.2] (Other) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3] 593 | ÷ 0378 ÷ AC01 ÷ # ÷ [0.2] (Other) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3] 594 | ÷ 0378 × 0308 ÷ AC01 ÷ # ÷ [0.2] (Other) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3] 595 | ÷ 0378 ÷ 231A ÷ # ÷ [0.2] (Other) ÷ [999.0] WATCH (ExtPict) ÷ [0.3] 596 | ÷ 0378 × 0308 ÷ 231A ÷ # ÷ [0.2] (Other) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] WATCH (ExtPict) ÷ [0.3] 597 | ÷ 0378 × 0300 ÷ # ÷ [0.2] (Other) × [9.0] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [0.3] 598 | ÷ 0378 × 0308 × 0300 ÷ # ÷ [0.2] (Other) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [0.3] 599 | ÷ 0378 × 200D ÷ # ÷ [0.2] (Other) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [0.3] 600 | ÷ 0378 × 0308 × 200D ÷ # ÷ [0.2] (Other) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [0.3] 601 | ÷ 0378 ÷ 0378 ÷ # ÷ [0.2] (Other) ÷ [999.0] (Other) ÷ [0.3] 602 | ÷ 0378 × 0308 ÷ 0378 ÷ # ÷ [0.2] (Other) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] (Other) ÷ [0.3] 603 | ÷ 000D × 000A ÷ 0061 ÷ 000A ÷ 0308 ÷ # ÷ [0.2] (CR) × [3.0] (LF) ÷ [4.0] LATIN SMALL LETTER A (Other) ÷ [5.0] (LF) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [0.3] 604 | ÷ 0061 × 0308 ÷ # ÷ [0.2] LATIN SMALL LETTER A (Other) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [0.3] 605 | ÷ 0020 × 200D ÷ 0646 ÷ # ÷ [0.2] SPACE (Other) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [999.0] ARABIC LETTER NOON (Other) ÷ [0.3] 606 | ÷ 0646 × 200D ÷ 0020 ÷ # ÷ [0.2] ARABIC LETTER NOON (Other) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [999.0] SPACE (Other) ÷ [0.3] 607 | ÷ 1100 × 1100 ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) × [6.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3] 608 | ÷ AC00 × 11A8 ÷ 1100 ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) × [7.0] HANGUL JONGSEONG KIYEOK (T) ÷ [999.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3] 609 | ÷ AC01 × 11A8 ÷ 1100 ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) × [8.0] HANGUL JONGSEONG KIYEOK (T) ÷ [999.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3] 610 | ÷ 1F1E6 × 1F1E7 ÷ 1F1E8 ÷ 0062 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [12.0] REGIONAL INDICATOR SYMBOL LETTER B (RI) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER C (RI) ÷ [999.0] LATIN SMALL LETTER B (Other) ÷ [0.3] 611 | ÷ 0061 ÷ 1F1E6 × 1F1E7 ÷ 1F1E8 ÷ 0062 ÷ # ÷ [0.2] LATIN SMALL LETTER A (Other) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [13.0] REGIONAL INDICATOR SYMBOL LETTER B (RI) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER C (RI) ÷ [999.0] LATIN SMALL LETTER B (Other) ÷ [0.3] 612 | ÷ 0061 ÷ 1F1E6 × 1F1E7 × 200D ÷ 1F1E8 ÷ 0062 ÷ # ÷ [0.2] LATIN SMALL LETTER A (Other) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [13.0] REGIONAL INDICATOR SYMBOL LETTER B (RI) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER C (RI) ÷ [999.0] LATIN SMALL LETTER B (Other) ÷ [0.3] 613 | ÷ 0061 ÷ 1F1E6 × 200D ÷ 1F1E7 × 1F1E8 ÷ 0062 ÷ # ÷ [0.2] LATIN SMALL LETTER A (Other) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER B (RI) × [13.0] REGIONAL INDICATOR SYMBOL LETTER C (RI) ÷ [999.0] LATIN SMALL LETTER B (Other) ÷ [0.3] 614 | ÷ 0061 ÷ 1F1E6 × 1F1E7 ÷ 1F1E8 × 1F1E9 ÷ 0062 ÷ # ÷ [0.2] LATIN SMALL LETTER A (Other) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [13.0] REGIONAL INDICATOR SYMBOL LETTER B (RI) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER C (RI) × [13.0] REGIONAL INDICATOR SYMBOL LETTER D (RI) ÷ [999.0] LATIN SMALL LETTER B (Other) ÷ [0.3] 615 | ÷ 0061 × 200D ÷ # ÷ [0.2] LATIN SMALL LETTER A (Other) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [0.3] 616 | ÷ 0061 × 0308 ÷ 0062 ÷ # ÷ [0.2] LATIN SMALL LETTER A (Other) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] LATIN SMALL LETTER B (Other) ÷ [0.3] 617 | ÷ 0061 × 0903 ÷ 0062 ÷ # ÷ [0.2] LATIN SMALL LETTER A (Other) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [999.0] LATIN SMALL LETTER B (Other) ÷ [0.3] 618 | ÷ 0061 ÷ 0600 × 0062 ÷ # ÷ [0.2] LATIN SMALL LETTER A (Other) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) × [9.2] LATIN SMALL LETTER B (Other) ÷ [0.3] 619 | ÷ 1F476 × 1F3FF ÷ 1F476 ÷ # ÷ [0.2] BABY (ExtPict) × [9.0] EMOJI MODIFIER FITZPATRICK TYPE-6 (Extend) ÷ [999.0] BABY (ExtPict) ÷ [0.3] 620 | ÷ 0061 × 1F3FF ÷ 1F476 ÷ # ÷ [0.2] LATIN SMALL LETTER A (Other) × [9.0] EMOJI MODIFIER FITZPATRICK TYPE-6 (Extend) ÷ [999.0] BABY (ExtPict) ÷ [0.3] 621 | ÷ 0061 × 1F3FF ÷ 1F476 × 200D × 1F6D1 ÷ # ÷ [0.2] LATIN SMALL LETTER A (Other) × [9.0] EMOJI MODIFIER FITZPATRICK TYPE-6 (Extend) ÷ [999.0] BABY (ExtPict) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) × [11.0] OCTAGONAL SIGN (ExtPict) ÷ [0.3] 622 | ÷ 1F476 × 1F3FF × 0308 × 200D × 1F476 × 1F3FF ÷ # ÷ [0.2] BABY (ExtPict) × [9.0] EMOJI MODIFIER FITZPATRICK TYPE-6 (Extend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) × [11.0] BABY (ExtPict) × [9.0] EMOJI MODIFIER FITZPATRICK TYPE-6 (Extend) ÷ [0.3] 623 | ÷ 1F6D1 × 200D × 1F6D1 ÷ # ÷ [0.2] OCTAGONAL SIGN (ExtPict) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) × [11.0] OCTAGONAL SIGN (ExtPict) ÷ [0.3] 624 | ÷ 0061 × 200D ÷ 1F6D1 ÷ # ÷ [0.2] LATIN SMALL LETTER A (Other) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [999.0] OCTAGONAL SIGN (ExtPict) ÷ [0.3] 625 | ÷ 2701 × 200D × 2701 ÷ # ÷ [0.2] UPPER BLADE SCISSORS (Other) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) × [11.0] UPPER BLADE SCISSORS (Other) ÷ [0.3] 626 | ÷ 0061 × 200D ÷ 2701 ÷ # ÷ [0.2] LATIN SMALL LETTER A (Other) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [999.0] UPPER BLADE SCISSORS (Other) ÷ [0.3] 627 | # 628 | # Lines: 602 629 | # 630 | # EOF 631 | -------------------------------------------------------------------------------- /elm.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "package", 3 | "name": "BrianHicks/elm-string-graphemes", 4 | "summary": "Do string operations based on graphemes instead of codepoints or bytes.", 5 | "license": "BSD-3-Clause", 6 | "version": "1.0.4", 7 | "exposed-modules": [ 8 | "String.Graphemes" 9 | ], 10 | "elm-version": "0.19.0 <= v < 0.20.0", 11 | "dependencies": { 12 | "elm/core": "1.0.2 <= v < 2.0.0" 13 | }, 14 | "test-dependencies": { 15 | "elm-explorations/test": "2.0.0 <= v < 3.0.0" 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /flake.lock: -------------------------------------------------------------------------------- 1 | { 2 | "nodes": { 3 | "flake-utils": { 4 | "inputs": { 5 | "systems": "systems" 6 | }, 7 | "locked": { 8 | "lastModified": 1687709756, 9 | "narHash": "sha256-Y5wKlQSkgEK2weWdOu4J3riRd+kV/VCgHsqLNTTWQ/0=", 10 | "owner": "numtide", 11 | "repo": "flake-utils", 12 | "rev": "dbabf0ca0c0c4bce6ea5eaf65af5cb694d2082c7", 13 | "type": "github" 14 | }, 15 | "original": { 16 | "owner": "numtide", 17 | "repo": "flake-utils", 18 | "type": "github" 19 | } 20 | }, 21 | "nixpkgs": { 22 | "locked": { 23 | "lastModified": 1687793116, 24 | "narHash": "sha256-6xRgZ2E9r/BNam87vMkHJ/0EPTTKzeNwhw3abKilEE4=", 25 | "owner": "NixOS", 26 | "repo": "nixpkgs", 27 | "rev": "9e4e0807d2142d17f463b26a8b796b3fe20a3011", 28 | "type": "github" 29 | }, 30 | "original": { 31 | "owner": "NixOS", 32 | "ref": "nixpkgs-unstable", 33 | "repo": "nixpkgs", 34 | "type": "github" 35 | } 36 | }, 37 | "root": { 38 | "inputs": { 39 | "flake-utils": "flake-utils", 40 | "nixpkgs": "nixpkgs" 41 | } 42 | }, 43 | "systems": { 44 | "locked": { 45 | "lastModified": 1681028828, 46 | "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", 47 | "owner": "nix-systems", 48 | "repo": "default", 49 | "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", 50 | "type": "github" 51 | }, 52 | "original": { 53 | "owner": "nix-systems", 54 | "repo": "default", 55 | "type": "github" 56 | } 57 | } 58 | }, 59 | "root": "root", 60 | "version": 7 61 | } 62 | -------------------------------------------------------------------------------- /flake.nix: -------------------------------------------------------------------------------- 1 | { 2 | inputs = { 3 | nixpkgs.url = "github:NixOS/nixpkgs/nixpkgs-unstable"; 4 | flake-utils.url = "github:numtide/flake-utils"; 5 | }; 6 | 7 | outputs = inputs: 8 | inputs.flake-utils.lib.eachDefaultSystem (system: 9 | let pkgs = import inputs.nixpkgs { inherit system; }; 10 | in { 11 | formatter = pkgs.nixpkgs-fmt; 12 | 13 | devShell = pkgs.mkShell { 14 | packages = [ 15 | pkgs.elmPackages.elm 16 | pkgs.elmPackages.elm-format 17 | pkgs.elmPackages.elm-test 18 | pkgs.elmPackages.elm-verify-examples 19 | pkgs.git 20 | pkgs.gnumake 21 | pkgs.nodePackages.uglify-js 22 | pkgs.python3 23 | ]; 24 | }; 25 | }); 26 | } 27 | -------------------------------------------------------------------------------- /script/generate-grapheme-break-test.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | import argparse 3 | import re 4 | import sys 5 | import textwrap 6 | 7 | parser = argparse.ArgumentParser() 8 | parser.add_argument('destination') 9 | args = parser.parse_args() 10 | 11 | module = args.destination[len('tests/'):-len('.elm')].replace('/', '.') 12 | 13 | out = [] 14 | out.append('module {} exposing (spec)'.format(module)) 15 | 16 | out.append('{-| Hey, this module was generated automatically. Please don\'t edit it.') 17 | out.append('') 18 | out.append('Run `make {}` instead!'.format(args.destination)) 19 | out.append('') 20 | out.append('-}') 21 | 22 | out.append('import Expect') 23 | out.append('import Test exposing (..)') 24 | out.append('import String.Graphemes as Grapheme') 25 | 26 | out.append('spec : Test') 27 | out.append('spec = ') 28 | out.append(' describe "grapheme breaks"') 29 | out.append(' [') 30 | 31 | tests = [] 32 | 33 | test = textwrap.dedent('''\ 34 | test "{index}: {comment}" <| 35 | \\_ -> 36 | {start_string} 37 | |> Grapheme.toList 38 | |> Expect.equal ({end_strings}) 39 | ''') 40 | 41 | for (i, line) in enumerate(sys.stdin.read().split('\n')): 42 | match = re.match(r'÷\s?(?P.+?)\s?÷\s?#\s+(?P.+)$', line) 43 | if match is None: 44 | continue 45 | 46 | data = match.groupdict() 47 | 48 | graphemes = [] 49 | for part in re.split(r'\s?÷\s?', data['test']): 50 | graphemes.append(''.join( 51 | '\\u{%s}' % codepoint 52 | for codepoint 53 | in re.split(r'\s?×\s?', part) 54 | )) 55 | 56 | tests.append(test.format( 57 | index=i, 58 | comment=data['comment'], 59 | start_string='"{}"'.format(''.join(graphemes)), 60 | end_strings='[ {} ]'.format(', '.join('"{}"'.format(grapheme) for grapheme in graphemes)) 61 | )) 62 | 63 | 64 | out.append('\n ,'.join(tests)) 65 | out.append(' ]') 66 | 67 | with open(args.destination, 'w') as fh: 68 | fh.write('\n'.join(out)) 69 | -------------------------------------------------------------------------------- /script/generate-matcher.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | import argparse 3 | import json 4 | import os.path as path 5 | import sys 6 | 7 | parser = argparse.ArgumentParser() 8 | parser.add_argument('destination') 9 | args = parser.parse_args() 10 | 11 | classes = json.load(sys.stdin) 12 | 13 | module = args.destination[len('src/'):-len('.elm')].replace('/', '.') 14 | class_ = module.split('.')[-1] 15 | 16 | if class_ not in classes: 17 | print('{} not in classes!'.format(class_)) 18 | sys.exit(1) 19 | 20 | out = [] 21 | out.append('module {} exposing (chars, match)'.format(module)) 22 | out.append('') 23 | out.append('{-| Hey, this module was generated automatically. Please don\'t edit it.') 24 | out.append('') 25 | out.append('Run `make {}` instead!'.format(args.destination)) 26 | out.append('') 27 | out.append('-}') 28 | out.append('') 29 | out.append('import String.Graphemes.Data as Data') 30 | out.append('import String.Graphemes.RangeDict as RangeDict exposing (RangeDict)') 31 | out.append('import String.Graphemes.RangeDict.Range as Range exposing (Range)') 32 | out.append('') 33 | out.append('') 34 | out.append('match : Char -> Bool') 35 | out.append('match c =') 36 | out.append(' RangeDict.member c chars') 37 | out.append('') 38 | out.append('') 39 | 40 | # CHARS 41 | 42 | chars = [] 43 | 44 | def elm_char(char): 45 | if char == '\n': 46 | return '\\n' 47 | elif char == '\r': 48 | return '\\r' 49 | elif char == '"': 50 | return '\\"' 51 | elif char == '\\': 52 | return '\\\\' 53 | elif class_ == 'Control': 54 | return '\\u{%s}' % hex(ord(char))[2:].zfill(4) 55 | else: 56 | return char 57 | 58 | for (i, match) in enumerate(classes[class_]): 59 | if match['kind'] == 'range': 60 | chars.append('2{}{}'.format(elm_char(match['start']), elm_char(match['end']))) 61 | elif match['kind'] == 'single': 62 | chars.append('1{}'.format(elm_char(match['codepoint']))) 63 | else: 64 | print('I don\'t know how to handle a "{}"!'.format(match['kind'])) 65 | sys.exit(1) 66 | 67 | out.append('chars : RangeDict Char Data.Class') 68 | out.append('chars =') 69 | out.append(' (Result.withDefault RangeDict.empty << Data.parser Data.{})'.format( 70 | class_.replace('_', ''), 71 | )) 72 | out.append(' "{}"'.format(''.join(chars))) 73 | 74 | # write out the final result 75 | 76 | with open(args.destination, 'w') as fh: 77 | fh.write('\n'.join(out)) 78 | -------------------------------------------------------------------------------- /script/ucd_overlap.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | from collections import defaultdict 3 | import json 4 | import re 5 | import sys 6 | 7 | CHARACTERS = defaultdict(list) 8 | 9 | CLASS_RE = re.compile(r'(?P[0-9A-F]{4,5})(\.\.(?P[0-9A-F]{4,5}))?\s+;\s*(?P\w+)\s*#\s(?P.+)$') 10 | 11 | # classes I don't care about since they are unused in our break algorithm. 12 | do_not_care = ['Emoji', 'Emoji_Presentation', 'Emoji_Modifier_Base', 'Emoji_Component', 'Emoji_Modifier'] 13 | 14 | for line in sys.stdin.read().split('\n'): 15 | out = CLASS_RE.match(line) 16 | if out is None: 17 | continue 18 | 19 | data = out.groupdict() 20 | 21 | if data['class'] in do_not_care: 22 | continue 23 | 24 | if data['end'] is not None: 25 | for i in range(int(data['start'], 16), int(data['end'], 16) + 1): 26 | CHARACTERS[i].append(data['class']) 27 | else: 28 | CHARACTERS[int(data['start'], 16)].append(data['class']) 29 | 30 | for (char, classes) in CHARACTERS.items(): 31 | if len(classes) != 1: 32 | print('{} is a member of {} classes: {}'.format( 33 | hex(char), 34 | len(classes), 35 | ', '.join(classes) 36 | )) 37 | -------------------------------------------------------------------------------- /script/ucd_to_json.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | from collections import defaultdict 3 | import json 4 | import re 5 | import sys 6 | 7 | SECTIONS = defaultdict(list) 8 | 9 | CLASS_RE = re.compile(r'(?P[0-9A-F]{4,5})(\.\.(?P[0-9A-F]{4,5}))?\s+;\s*(?P\w+)\s*#\s(?P.+)$') 10 | 11 | for line in sys.stdin.read().split('\n'): 12 | out = CLASS_RE.match(line) 13 | if out is None: 14 | continue 15 | 16 | data = out.groupdict() 17 | 18 | if data['end'] is not None: 19 | out = { 20 | 'kind': 'range', 21 | 'start': chr(int(data['start'], 16)), 22 | 'end': chr(int(data['end'], 16)), 23 | 'comment': data['comment'], 24 | } 25 | else: 26 | out = { 27 | 'kind': 'single', 28 | 'codepoint': chr(int(data['start'], 16)), 29 | 'comment': data['comment'], 30 | } 31 | 32 | SECTIONS[data['class']].append(out) 33 | 34 | json.dump(SECTIONS, sys.stdout, indent=4) 35 | -------------------------------------------------------------------------------- /shell.nix: -------------------------------------------------------------------------------- 1 | let 2 | sources = import ./nix/sources.nix; 3 | nixpkgs = import sources.nixpkgs { }; 4 | niv = import sources.niv { }; 5 | in with nixpkgs; 6 | stdenv.mkDerivation { 7 | name = "elm-unicode-segmentation"; 8 | buildInputs = [ 9 | elmPackages.elm 10 | elmPackages.elm-format 11 | elmPackages.elm-test 12 | elmPackages.elm-verify-examples 13 | git 14 | gnumake 15 | niv.niv 16 | nodePackages.uglify-js 17 | python37 18 | ]; 19 | } 20 | -------------------------------------------------------------------------------- /size-benchmarks/elm.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "application", 3 | "source-directories": [ 4 | "src", 5 | "../src" 6 | ], 7 | "elm-version": "0.19.0", 8 | "dependencies": { 9 | "direct": { 10 | "elm/browser": "1.0.1", 11 | "elm/core": "1.0.2", 12 | "elm/html": "1.0.0" 13 | }, 14 | "indirect": { 15 | "elm/json": "1.1.3", 16 | "elm/time": "1.0.0", 17 | "elm/url": "1.0.0", 18 | "elm/virtual-dom": "1.0.2" 19 | } 20 | }, 21 | "test-dependencies": { 22 | "direct": {}, 23 | "indirect": {} 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /size-benchmarks/report.txt: -------------------------------------------------------------------------------- 1 | Optimized: 86.12kb to 122.94kb (+36.83kb) 2 | Uglified: 34.69kb to 51.62kb (+16.93kb) 3 | Gzipped: 11.59kb to 20.16kb (+8.57kb) 4 | -------------------------------------------------------------------------------- /size-benchmarks/src/WithSegmentation.elm: -------------------------------------------------------------------------------- 1 | module WithSegmentation exposing (main) 2 | 3 | import Html exposing (Html) 4 | import String.Graphemes as Graphemes 5 | 6 | 7 | main : Html msg 8 | main = 9 | "\u{1F9B8}\u{1F3FD}\u{200D}♂️" 10 | |> Graphemes.toList 11 | |> String.concat 12 | |> Html.text 13 | -------------------------------------------------------------------------------- /size-benchmarks/src/WithoutSegmentation.elm: -------------------------------------------------------------------------------- 1 | module WithoutSegmentation exposing (main) 2 | 3 | import Html exposing (Html) 4 | 5 | 6 | main : Html msg 7 | main = 8 | "\u{1F9B8}\u{1F3FD}\u{200D}♂️" 9 | |> String.toList 10 | |> String.fromList 11 | |> Html.text 12 | -------------------------------------------------------------------------------- /size-benchmarks/stats.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | import subprocess 3 | 4 | with_filename = 'withSegmentation.js' 5 | without_filename = 'withoutSegmentation.js' 6 | 7 | def compare(kind, filename_a, filename_b): 8 | a_contents = open(filename_a, "rb").read() 9 | b_contents = open(filename_b, "rb").read() 10 | 11 | print('{}:\t{:.2f}kb to {:.2f}kb\t({:+.2f}kb)'.format( 12 | kind, 13 | len(a_contents) / 1024, 14 | len(b_contents) / 1024, 15 | (len(b_contents) - len(a_contents)) / 1024, 16 | )) 17 | 18 | # uncompressed 19 | 20 | subprocess.check_output(['elm', 'make', '--optimize', '--output={}'.format(with_filename), 'src/WithSegmentation.elm']) 21 | subprocess.check_output(['elm', 'make', '--optimize', '--output={}'.format(without_filename), 'src/WithoutSegmentation.elm']) 22 | 23 | compare('Optimized', without_filename, with_filename) 24 | 25 | # uglify 26 | 27 | def uglify(filename, out): 28 | compressed = subprocess.check_output(['uglifyjs', filename, '--compress', 'pure_funcs=[F2,F3,F4,F5,F6,F7,F8,F9,A2,A3,A4,A5,A6,A7,A8,A9],pure_getters,keep_fargs=false,unsafe_comps,unsafe']) 29 | subprocess.run(['uglifyjs', filename, '--mangle', '--output={}'.format(out)], input=compressed) 30 | 31 | with_filename_min = with_filename.replace('.js', '.min.js') 32 | without_filename_min = without_filename.replace('.js', '.min.js') 33 | 34 | uglify(with_filename, with_filename_min) 35 | uglify(without_filename, without_filename_min) 36 | 37 | compare('Uglified', without_filename_min, with_filename_min) 38 | 39 | # gzip 40 | 41 | with_filename_min_gz = with_filename_min + '.gz' 42 | without_filename_min_gz = without_filename_min + '.gz' 43 | 44 | subprocess.check_call(['gzip', '-9', '-k', '-f', with_filename_min]) 45 | subprocess.check_call(['gzip', '-9', '-k', '-f', without_filename_min]) 46 | 47 | compare('Gzipped', without_filename_min_gz, with_filename_min_gz) 48 | -------------------------------------------------------------------------------- /src/String/Graphemes.elm: -------------------------------------------------------------------------------- 1 | module String.Graphemes exposing 2 | ( isEmpty, length, reverse, repeat, replace 3 | , append, concat, split, join, words, lines 4 | , slice, left, right, dropLeft, dropRight 5 | , contains, startsWith, endsWith, indexes, indices 6 | , toInt, fromInt 7 | , toFloat, fromFloat 8 | , fromChar, cons, uncons 9 | , toList, fromList 10 | , toUpper, toLower, pad, padLeft, padRight, trim, trimLeft, trimRight 11 | , map, filter, foldl, foldr, any, all 12 | ) 13 | 14 | {-| A built-in representation for efficient string manipulation. String literals 15 | are enclosed in `"double quotes"`. Strings are _not_ lists of characters. 16 | 17 | 18 | # Strings 19 | 20 | @docs isEmpty, length, reverse, repeat, replace 21 | 22 | 23 | # Building and Splitting 24 | 25 | @docs append, concat, split, join, words, lines 26 | 27 | 28 | # Get Substrings 29 | 30 | @docs slice, left, right, dropLeft, dropRight 31 | 32 | 33 | # Check for Substrings 34 | 35 | @docs contains, startsWith, endsWith, indexes, indices 36 | 37 | 38 | # Int Conversions 39 | 40 | @docs toInt, fromInt 41 | 42 | 43 | # Float Conversions 44 | 45 | @docs toFloat, fromFloat 46 | 47 | 48 | # Char Conversions 49 | 50 | @docs fromChar, cons, uncons 51 | 52 | 53 | # List Conversions 54 | 55 | @docs toList, fromList 56 | 57 | 58 | # Formatting 59 | 60 | Cosmetic operations such as padding with extra characters or trimming whitespace. 61 | 62 | @docs toUpper, toLower, pad, padLeft, padRight, trim, trimLeft, trimRight 63 | 64 | 65 | # Higher-Order Functions 66 | 67 | @docs map, filter, foldl, foldr, any, all 68 | 69 | -} 70 | 71 | import Array 72 | import String.Graphemes.Parser as Parser 73 | 74 | 75 | 76 | -- STRINGS 77 | 78 | 79 | {-| Determine if a string is empty. 80 | 81 | isEmpty "" --> True 82 | 83 | isEmpty "the world" --> False 84 | 85 | -} 86 | isEmpty : String -> Bool 87 | isEmpty = 88 | String.isEmpty 89 | 90 | 91 | {-| Get the length of a string. 92 | 93 | length "innumerable" --> 11 94 | 95 | length "" --> 0 96 | 97 | length "🇨🇦" --> 1 98 | 99 | -} 100 | length : String -> Int 101 | length = 102 | foldl (\_ len -> len + 1) 0 103 | 104 | 105 | {-| Reverse a string. 106 | 107 | reverse "stressed" --> "desserts" 108 | 109 | reverse "🇨🇦🇲🇽" --> "🇲🇽🇨🇦" 110 | 111 | -} 112 | reverse : String -> String 113 | reverse = 114 | toList >> List.reverse >> concat 115 | 116 | 117 | {-| Repeat a string _n_ times. 118 | 119 | repeat 3 "ha" --> "hahaha" 120 | 121 | -} 122 | repeat : Int -> String -> String 123 | repeat = 124 | String.repeat 125 | 126 | 127 | {-| Replace all occurrences of some substring. 128 | 129 | replace "." "-" "Json.Decode.succeed" --> "Json-Decode-succeed" 130 | 131 | replace "," "/" "a,b,c,d,e" --> "a/b/c/d/e" 132 | 133 | **Note:** If you need more advanced replacements, check out the 134 | [`elm/parser`][parser] or [`elm/regex`][regex] package. 135 | 136 | [parser]: /packages/elm/parser/latest 137 | [regex]: /packages/elm/regex/latest 138 | 139 | -} 140 | replace : String -> String -> String -> String 141 | replace = 142 | String.replace 143 | 144 | 145 | 146 | -- BUILDING AND SPLITTING 147 | 148 | 149 | {-| Append two strings. You can also use [the `(++)` operator](Basics#++) 150 | to do this. 151 | 152 | append "butter" "fly" --> "butterfly" 153 | 154 | -} 155 | append : String -> String -> String 156 | append = 157 | String.append 158 | 159 | 160 | {-| Concatenate many strings into one. 161 | 162 | concat [ "never", "the", "less" ] --> "nevertheless" 163 | 164 | -} 165 | concat : List String -> String 166 | concat = 167 | String.concat 168 | 169 | 170 | {-| Split a string using a given separator. 171 | 172 | split "," "cat,dog,cow" --> [ "cat", "dog", "cow" ] 173 | 174 | split "/" "home/evan/Desktop/" --> [ "home", "evan", "Desktop", "" ] 175 | 176 | **Note:** this will split a string very literally—including breaking grapheme 177 | boundaries. If this causes problems for you, please open an issue. 178 | 179 | -} 180 | split : String -> String -> List String 181 | split = 182 | String.split 183 | 184 | 185 | {-| Put many strings together with a given separator. 186 | 187 | join "a" [ "H", "w", "ii", "n" ] --> "Hawaiian" 188 | 189 | join " " [ "cat", "dog", "cow" ] --> "cat dog cow" 190 | 191 | join "/" [ "home", "evan", "Desktop" ] --> "home/evan/Desktop" 192 | 193 | -} 194 | join : String -> List String -> String 195 | join = 196 | String.join 197 | 198 | 199 | {-| Break a string into words, splitting on chunks of whitespace. 200 | 201 | words "How are \t you? \n Good?" --> [ "How", "are", "you?", "Good?" ] 202 | 203 | -} 204 | words : String -> List String 205 | words = 206 | String.words 207 | 208 | 209 | {-| Break a string into lines, splitting on newlines. 210 | 211 | lines "How are you?\nGood?" --> [ "How are you?", "Good?" ] 212 | 213 | -} 214 | lines : String -> List String 215 | lines = 216 | String.lines 217 | 218 | 219 | 220 | -- SUBSTRINGS 221 | 222 | 223 | {-| Take a substring given a start and end index. Negative indexes 224 | are taken starting from the _end_ of the list. 225 | 226 | slice 7 9 "snakes on a plane!" --> "on" 227 | 228 | slice 0 6 "snakes on a plane!" --> "snakes" 229 | 230 | slice 0 -7 "snakes on a plane!" --> "snakes on a" 231 | 232 | slice -6 -1 "snakes on a plane!" --> "plane" 233 | 234 | -} 235 | slice : Int -> Int -> String -> String 236 | slice start end string = 237 | -- performance note: this is actually way faster than calculating lengths 238 | -- and using List.take and List.drop—like twice as fast in the non-negative 239 | -- case and even faster when indexing from the end! 240 | string 241 | |> toList 242 | |> Array.fromList 243 | |> Array.slice start end 244 | |> Array.toList 245 | |> concat 246 | 247 | 248 | {-| Take _n_ characters from the left side of a string. 249 | 250 | left 2 "Mulder" --> "Mu" 251 | 252 | -} 253 | left : Int -> String -> String 254 | left n string = 255 | if n < 1 then 256 | "" 257 | 258 | else 259 | slice 0 n string 260 | 261 | 262 | {-| Take _n_ characters from the right side of a string. 263 | 264 | right 2 "Scully" --> "ly" 265 | 266 | -} 267 | right : Int -> String -> String 268 | right n string = 269 | if n < 1 then 270 | "" 271 | 272 | else 273 | slice -n (length string) string 274 | 275 | 276 | {-| Drop _n_ characters from the left side of a string. 277 | 278 | dropLeft 2 "The Lone Gunmen" --> "e Lone Gunmen" 279 | 280 | -} 281 | dropLeft : Int -> String -> String 282 | dropLeft n string = 283 | if n < 1 then 284 | string 285 | 286 | else 287 | slice n (length string) string 288 | 289 | 290 | {-| Drop _n_ characters from the right side of a string. 291 | 292 | dropRight 2 "Cigarette Smoking Man" --> "Cigarette Smoking M" 293 | 294 | -} 295 | dropRight : Int -> String -> String 296 | dropRight n string = 297 | if n < 1 then 298 | string 299 | 300 | else 301 | slice 0 -n string 302 | 303 | 304 | 305 | -- DETECT SUBSTRINGS 306 | 307 | 308 | {-| See if the second string contains the first one. 309 | 310 | contains "the" "theory" --> True 311 | 312 | contains "hat" "theory" --> False 313 | 314 | contains "THE" "theory" --> False 315 | 316 | -} 317 | contains : String -> String -> Bool 318 | contains = 319 | String.contains 320 | 321 | 322 | {-| See if the second string starts with the first one. 323 | 324 | startsWith "the" "theory" --> True 325 | 326 | startsWith "ory" "theory" --> False 327 | 328 | -} 329 | startsWith : String -> String -> Bool 330 | startsWith = 331 | String.startsWith 332 | 333 | 334 | {-| See if the second string ends with the first one. 335 | 336 | endsWith "the" "theory" --> False 337 | 338 | endsWith "ory" "theory" --> True 339 | 340 | -} 341 | endsWith : String -> String -> Bool 342 | endsWith = 343 | String.endsWith 344 | 345 | 346 | {-| Get all of the indexes for a substring in another string. 347 | 348 | indexes "i" "Mississippi" --> [ 1, 4, 7, 10 ] 349 | 350 | indexes "ss" "Mississippi" --> [ 2, 5 ] 351 | 352 | indexes "needle" "haystack" --> [] 353 | 354 | -} 355 | indexes : String -> String -> List Int 356 | indexes = 357 | String.indexes 358 | 359 | 360 | {-| Alias for `indexes`. 361 | -} 362 | indices : String -> String -> List Int 363 | indices = 364 | String.indexes 365 | 366 | 367 | 368 | -- FORMATTING 369 | 370 | 371 | {-| Convert a string to all upper case. Useful for case-insensitive comparisons 372 | and VIRTUAL YELLING. 373 | 374 | toUpper "skinner" --> "SKINNER" 375 | 376 | -} 377 | toUpper : String -> String 378 | toUpper = 379 | String.toUpper 380 | 381 | 382 | {-| Convert a string to all lower case. Useful for case-insensitive comparisons. 383 | 384 | toLower "X-FILES" --> "x-files" 385 | 386 | -} 387 | toLower : String -> String 388 | toLower = 389 | String.toLower 390 | 391 | 392 | {-| Pad a string on both sides until it has a given length. 393 | 394 | pad 5 ' ' "1" --> " 1 " 395 | 396 | pad 5 ' ' "11" --> " 11 " 397 | 398 | pad 5 ' ' "121" --> " 121 " 399 | 400 | -} 401 | pad : Int -> Char -> String -> String 402 | pad n char string = 403 | let 404 | half = 405 | Basics.toFloat (n - length string) / 2 406 | in 407 | repeat (ceiling half) (fromChar char) ++ string ++ repeat (floor half) (fromChar char) 408 | 409 | 410 | {-| Pad a string on the left until it has a given length. 411 | 412 | padLeft 5 '.' "1" --> "....1" 413 | 414 | padLeft 5 '.' "11" --> "...11" 415 | 416 | padLeft 5 '.' "121" --> "..121" 417 | 418 | -} 419 | padLeft : Int -> Char -> String -> String 420 | padLeft n char string = 421 | repeat (n - length string) (fromChar char) ++ string 422 | 423 | 424 | {-| Pad a string on the right until it has a given length. 425 | 426 | padRight 5 '.' "1" --> "1...." 427 | 428 | padRight 5 '.' "11" --> "11..." 429 | 430 | padRight 5 '.' "121" --> "121.." 431 | 432 | -} 433 | padRight : Int -> Char -> String -> String 434 | padRight n char string = 435 | string ++ repeat (n - length string) (fromChar char) 436 | 437 | 438 | {-| Get rid of whitespace on both sides of a string. 439 | 440 | trim " hats \n" --> "hats" 441 | 442 | -} 443 | trim : String -> String 444 | trim = 445 | String.trim 446 | 447 | 448 | {-| Get rid of whitespace on the left of a string. 449 | 450 | trimLeft " hats \n" --> "hats \n" 451 | 452 | -} 453 | trimLeft : String -> String 454 | trimLeft = 455 | String.trimLeft 456 | 457 | 458 | {-| Get rid of whitespace on the right of a string. 459 | 460 | trimRight " hats \n" --> " hats" 461 | 462 | -} 463 | trimRight : String -> String 464 | trimRight = 465 | String.trimRight 466 | 467 | 468 | 469 | -- INT CONVERSIONS 470 | 471 | 472 | {-| Try to convert a string into an int, failing on improperly formatted strings. 473 | 474 | String.toInt "123" --> Just 123 475 | 476 | String.toInt "-42" --> Just -42 477 | 478 | String.toInt "3.1" --> Nothing 479 | 480 | String.toInt "31a" --> Nothing 481 | 482 | If you are extracting a number from some raw user input, you will typically 483 | want to use [`Maybe.withDefault`](Maybe#withDefault) to handle bad data: 484 | 485 | Maybe.withDefault 0 (String.toInt "42") --> 42 486 | 487 | Maybe.withDefault 0 (String.toInt "ab") --> 0 488 | 489 | -} 490 | toInt : String -> Maybe Int 491 | toInt = 492 | String.toInt 493 | 494 | 495 | {-| Convert an `Int` to a `String`. 496 | 497 | String.fromInt 123 --> "123" 498 | 499 | String.fromInt -42 --> "-42" 500 | 501 | Check out [`Debug.toString`](Debug#toString) to convert _any_ value to a string 502 | for debugging purposes. 503 | 504 | -} 505 | fromInt : Int -> String 506 | fromInt = 507 | String.fromInt 508 | 509 | 510 | 511 | -- FLOAT CONVERSIONS 512 | 513 | 514 | {-| Try to convert a string into a float, failing on improperly formatted strings. 515 | -} 516 | toFloat : String -> Maybe Float 517 | toFloat = 518 | String.toFloat 519 | 520 | 521 | {-| Convert a `Float` to a `String`. 522 | 523 | String.fromFloat 123 --> "123" 524 | 525 | String.fromFloat -42 --> "-42" 526 | 527 | String.fromFloat 3.9 --> "3.9" 528 | 529 | Check out [`Debug.toString`](Debug#toString) to convert _any_ value to a string 530 | for debugging purposes. 531 | 532 | -} 533 | fromFloat : Float -> String 534 | fromFloat = 535 | String.fromFloat 536 | 537 | 538 | 539 | -- LIST CONVERSIONS 540 | 541 | 542 | {-| Convert a string to a list of characters. 543 | 544 | toList "abc" --> [ "a", "b", "c" ] 545 | 546 | toList "🙈🙉🙊" --> [ "🙈", "🙉", "🙊" ] 547 | 548 | -} 549 | toList : String -> List String 550 | toList = 551 | foldr (::) [] 552 | 553 | 554 | {-| Convert a list of graphemes into a String. Can be useful if you 555 | want to create a string primarily by consing, perhaps for decoding 556 | something. 557 | 558 | fromList [ "a", "b", "c" ] --> "abc" 559 | 560 | fromList [ "🙈", "🙉", "🙊" ] --> "🙈🙉🙊" 561 | 562 | -} 563 | fromList : List String -> String 564 | fromList = 565 | concat 566 | 567 | 568 | 569 | -- CHAR CONVERSIONS 570 | 571 | 572 | {-| Create a string from a given character. 573 | 574 | fromChar 'a' --> "a" 575 | 576 | -} 577 | fromChar : Char -> String 578 | fromChar = 579 | String.fromChar 580 | 581 | 582 | {-| Add a character to the beginning of a string. 583 | 584 | cons 'T' "he truth is out there" --> "The truth is out there" 585 | 586 | -} 587 | cons : Char -> String -> String 588 | cons = 589 | String.cons 590 | 591 | 592 | {-| Split a non-empty string into its head and tail. This lets you 593 | pattern match on strings exactly as you would with lists. 594 | 595 | uncons "abc" --> Just ( "a", "bc" ) 596 | 597 | uncons "" --> Nothing 598 | 599 | -} 600 | uncons : String -> Maybe ( String, String ) 601 | uncons = 602 | Parser.uncons 603 | 604 | 605 | 606 | -- HIGHER-ORDER FUNCTIONS 607 | 608 | 609 | {-| Transform every grapheme in a string 610 | -} 611 | map : (String -> String) -> String -> String 612 | map mapper string = 613 | string 614 | |> foldr (\grapheme acc -> mapper grapheme :: acc) [] 615 | |> String.concat 616 | 617 | 618 | {-| Keep only the graphemes that pass the test. 619 | 620 | filter (String.all Char.isDigit) "R2-D2" --> "22" 621 | 622 | -} 623 | filter : (String -> Bool) -> String -> String 624 | filter test string = 625 | string 626 | |> foldr 627 | (\grapheme acc -> 628 | if test grapheme then 629 | grapheme :: acc 630 | 631 | else 632 | acc 633 | ) 634 | [] 635 | |> String.concat 636 | 637 | 638 | {-| Reduce a string from the left. 639 | 640 | foldl (++) "" "time" --> "emit" 641 | 642 | -} 643 | foldl : (String -> b -> b) -> b -> String -> b 644 | foldl = 645 | Parser.foldl 646 | 647 | 648 | {-| Reduce a string from the right. 649 | 650 | foldr (++) "" "time" --> "time" 651 | 652 | -} 653 | foldr : (String -> b -> b) -> b -> String -> b 654 | foldr fn state string = 655 | string 656 | |> foldl (::) [] 657 | |> List.foldl fn state 658 | 659 | 660 | {-| Determine whether _any_ graphemes pass the test. 661 | 662 | any (String.all Char.isDigit) "90210" --> True 663 | 664 | any (String.all Char.isDigit) "R2-D2" --> True 665 | 666 | any (String.all Char.isDigit) "heart" --> False 667 | 668 | -} 669 | any : (String -> Bool) -> String -> Bool 670 | any test string = 671 | foldl (\grapheme acc -> acc || test grapheme) False string 672 | 673 | 674 | {-| Determine whether _all_ graphemes pass the test. 675 | 676 | all (String.all Char.isDigit) "90210" --> True 677 | 678 | all (String.all Char.isDigit) "R2-D2" --> False 679 | 680 | all (String.all Char.isDigit) "heart" --> False 681 | 682 | -} 683 | all : (String -> Bool) -> String -> Bool 684 | all test string = 685 | foldl (\grapheme acc -> acc && test grapheme) True string 686 | -------------------------------------------------------------------------------- /src/String/Graphemes/Data.elm: -------------------------------------------------------------------------------- 1 | module String.Graphemes.Data exposing (Class(..), parser) 2 | 3 | import String.Graphemes.RangeDict as RangeDict exposing (RangeDict) 4 | import String.Graphemes.RangeDict.Range as Range 5 | 6 | 7 | type Class 8 | = CR 9 | | LF 10 | | Control 11 | | Prepend 12 | | RegionalIndicator 13 | | L 14 | | V 15 | | T 16 | | LV 17 | | LVT 18 | | ExtendedPictographic 19 | | Extend 20 | | SpacingMark 21 | | ZWJ 22 | 23 | 24 | type ParserState 25 | = Error String 26 | | Empty 27 | | One 28 | | Two (Maybe Char) 29 | 30 | 31 | parser : Class -> String -> Result String (RangeDict Char Class) 32 | parser value source = 33 | case String.foldl (handleChar value) ( Empty, RangeDict.empty ) source of 34 | ( Empty, out ) -> 35 | Ok out 36 | 37 | ( Error err, _ ) -> 38 | Err err 39 | 40 | ( One, _ ) -> 41 | Err "ended with an empty One" 42 | 43 | ( Two _, _ ) -> 44 | Err "ended with an empty Two" 45 | 46 | 47 | handleChar : Class -> Char -> ( ParserState, RangeDict Char Class ) -> ( ParserState, RangeDict Char Class ) 48 | handleChar value char ( parserState, rangeDict ) = 49 | case ( parserState, char ) of 50 | ( Error _, _ ) -> 51 | ( parserState, rangeDict ) 52 | 53 | ( Empty, '1' ) -> 54 | ( One, rangeDict ) 55 | 56 | ( Empty, '2' ) -> 57 | ( Two Nothing, rangeDict ) 58 | 59 | ( Empty, _ ) -> 60 | ( Error "expected to see a parsing directive like '1' or '2'", rangeDict ) 61 | 62 | ( One, _ ) -> 63 | ( Empty, RangeDict.insert (Range.point char) value rangeDict ) 64 | 65 | ( Two Nothing, _ ) -> 66 | ( Two (Just char), rangeDict ) 67 | 68 | ( Two (Just low), _ ) -> 69 | ( Empty, RangeDict.insert (Range.range low char) value rangeDict ) 70 | -------------------------------------------------------------------------------- /src/String/Graphemes/Data/CR.elm: -------------------------------------------------------------------------------- 1 | module String.Graphemes.Data.CR exposing (chars, match) 2 | 3 | {-| Hey, this module was generated automatically. Please don't edit it. 4 | 5 | Run `make src/String/Graphemes/Data/CR.elm` instead! 6 | 7 | -} 8 | 9 | import String.Graphemes.Data as Data 10 | import String.Graphemes.RangeDict as RangeDict exposing (RangeDict) 11 | import String.Graphemes.RangeDict.Range as Range exposing (Range) 12 | 13 | 14 | match : Char -> Bool 15 | match c = 16 | RangeDict.member c chars 17 | 18 | 19 | chars : RangeDict Char Data.Class 20 | chars = 21 | (Result.withDefault RangeDict.empty << Data.parser Data.CR) 22 | "1\r" -------------------------------------------------------------------------------- /src/String/Graphemes/Data/Control.elm: -------------------------------------------------------------------------------- 1 | module String.Graphemes.Data.Control exposing (chars, match) 2 | 3 | {-| Hey, this module was generated automatically. Please don't edit it. 4 | 5 | Run `make src/String/Graphemes/Data/Control.elm` instead! 6 | 7 | -} 8 | 9 | import String.Graphemes.Data as Data 10 | import String.Graphemes.RangeDict as RangeDict exposing (RangeDict) 11 | import String.Graphemes.RangeDict.Range as Range exposing (Range) 12 | 13 | 14 | match : Char -> Bool 15 | match c = 16 | RangeDict.member c chars 17 | 18 | 19 | chars : RangeDict Char Data.Class 20 | chars = 21 | (Result.withDefault RangeDict.empty << Data.parser Data.Control) 22 | "2\u{0000}\u{0009}2\u{000b}\u{000c}2\u{000e}\u{001f}2\u{007f}\u{009f}1\u{00ad}1\u{061c}1\u{180e}1\u{200b}2\u{200e}\u{200f}1\u{2028}1\u{2029}2\u{202a}\u{202e}2\u{2060}\u{2064}1\u{2065}2\u{2066}\u{206f}1\u{feff}2\u{fff0}\u{fff8}2\u{fff9}\u{fffb}2\u{13430}\u{1343f}2\u{1bca0}\u{1bca3}2\u{1d173}\u{1d17a}1\u{e0000}1\u{e0001}2\u{e0002}\u{e001f}2\u{e0080}\u{e00ff}2\u{e01f0}\u{e0fff}" -------------------------------------------------------------------------------- /src/String/Graphemes/Data/Extend.elm: -------------------------------------------------------------------------------- 1 | module String.Graphemes.Data.Extend exposing (chars, match) 2 | 3 | {-| Hey, this module was generated automatically. Please don't edit it. 4 | 5 | Run `make src/String/Graphemes/Data/Extend.elm` instead! 6 | 7 | -} 8 | 9 | import String.Graphemes.Data as Data 10 | import String.Graphemes.RangeDict as RangeDict exposing (RangeDict) 11 | import String.Graphemes.RangeDict.Range as Range exposing (Range) 12 | 13 | 14 | match : Char -> Bool 15 | match c = 16 | RangeDict.member c chars 17 | 18 | 19 | chars : RangeDict Char Data.Class 20 | chars = 21 | (Result.withDefault RangeDict.empty << Data.parser Data.Extend) 22 | "2̀ͯ2҃҇2҈҉2ֽ֑1ֿ2ׁׂ2ׅׄ1ׇ2ؚؐ2ًٟ1ٰ2ۖۜ2۟ۤ2ۧۨ2۪ۭ1ܑ2ܰ݊2ަް2߫߳1߽2ࠖ࠙2ࠛࠣ2ࠥࠧ2ࠩ࠭2࡙࡛2࢘࢟2࣊࣡2ࣣं1ऺ1़2ुै1्2॑ॗ2ॢॣ1ঁ1়1া2ুৄ1্1ৗ2ৢৣ1৾2ਁਂ1਼2ੁੂ2ੇੈ2ੋ੍1ੑ2ੰੱ1ੵ2ઁં1઼2ુૅ2ેૈ1્2ૢૣ2ૺ૿1ଁ1଼1ା1ି2ୁୄ1୍2୕ୖ1ୗ2ୢୣ1ஂ1ா1ீ1்1ௗ1ఀ1ఄ1఼2ాీ2ెై2ొ్2ౕౖ2ౢౣ1ಁ1಼1ಿ1ೂ1ೆ2ೌ್2ೕೖ2ೢೣ2ഀഁ2഻഼1ാ2ുൄ1്1ൗ2ൢൣ1ඁ1්1ා2ිු1ූ1ෟ1ั2ิฺ2็๎1ັ2ິຼ2່໎2༘༙1༵1༷1༹2ཱཾ2྄ྀ2྆྇2ྍྗ2ྙྼ1࿆2ိူ2ဲ့2္်2ွှ2ၘၙ2ၞၠ2ၱၴ1ႂ2ႅႆ1ႍ1ႝ2፝፟2ᜒ᜔2ᜲᜳ2ᝒᝓ2ᝲᝳ2឴឵2ិួ1ំ2៉៓1៝2᠋᠍1᠏2ᢅᢆ1ᢩ2ᤠᤢ2ᤧᤨ1ᤲ2᤻᤹2ᨘᨗ1ᨛ1ᩖ2ᩘᩞ1᩠1ᩢ2ᩥᩬ2ᩳ᩼1᩿2᪽᪰1᪾2ᪿᫎ2ᬀᬃ1᬴1ᬵ2ᬶᬺ1ᬼ1ᭂ2᭫᭳2ᮀᮁ2ᮢᮥ2ᮨᮩ2᮫ᮭ1᯦2ᯨᯩ1ᯭ2ᯯᯱ2ᰬᰳ2ᰶ᰷2᳐᳒2᳔᳠2᳢᳨1᳭1᳴2᳸᳹2᷿᷀1‌2⃐⃜2⃝⃠1⃡2⃢⃤2⃥⃰2⳯⳱1⵿2ⷠⷿ2〪〭2〮〯2゙゚1꙯2꙰꙲2ꙴ꙽2ꚞꚟ2꛰꛱1ꠂ1꠆1ꠋ2ꠥꠦ1꠬2꣄ꣅ2꣠꣱1ꣿ2ꤦ꤭2ꥇꥑ2ꦀꦂ1꦳2ꦶꦹ2ꦼꦽ1ꧥ2ꨩꨮ2ꨱꨲ2ꨵꨶ1ꩃ1ꩌ1ꩼ1ꪰ2ꪴꪲ2ꪷꪸ2ꪾ꪿1꫁2ꫬꫭ1꫶1ꯥ1ꯨ1꯭1ﬞ2︀️2︠︯2゙゚1𐇽1𐋠2𐍶𐍺2𐨁𐨃2𐨅𐨆2𐨌𐨏2𐨺𐨸1𐨿2𐫦𐫥2𐴤𐴧2𐺫𐺬2𐻽𐻿2𐽆𐽐2𐾅𐾂1𑀁2𑀸𑁆1𑁰2𑁳𑁴2𑁿𑂁2𑂳𑂶2𑂺𑂹1𑃂2𑄀𑄂2𑄧𑄫2𑄭𑄴1𑅳2𑆀𑆁2𑆶𑆾2𑇉𑇌1𑇏2𑈯𑈱1𑈴2𑈶𑈷1𑈾1𑉁1𑋟2𑋣𑋪2𑌀𑌁2𑌻𑌼1𑌾1𑍀1𑍗2𑍦𑍬2𑍰𑍴2𑐸𑐿2𑑂𑑄1𑑆1𑑞1𑒰2𑒳𑒸1𑒺1𑒽2𑒿𑓀2𑓃𑓂1𑖯2𑖲𑖵2𑖼𑖽2𑗀𑖿2𑗜𑗝2𑘳𑘺1𑘽2𑘿𑙀1𑚫1𑚭2𑚰𑚵1𑚷2𑜝𑜟2𑜢𑜥2𑜧𑜫2𑠯𑠷2𑠺𑠹1𑤰2𑤻𑤼1𑤾1𑥃2𑧔𑧗2𑧚𑧛1𑧠2𑨁𑨊2𑨳𑨸2𑨻𑨾1𑩇2𑩑𑩖2𑩙𑩛2𑪊𑪖2𑪘𑪙2𑰰𑰶2𑰸𑰽1𑰿2𑲒𑲧2𑲪𑲰2𑲲𑲳2𑲵𑲶2𑴱𑴶1𑴺2𑴼𑴽2𑴿𑵅1𑵇2𑶐𑶑1𑶕1𑶗2𑻳𑻴2𑼀𑼁2𑼶𑼺1𑽀1𑽂1𓑀2𓑇𓑕2𖫰𖫴2𖬰𖬶1𖽏2𖾏𖾒1𖿤2𛲝𛲞2𜼀𜼭2𜼰𜽆1𝅥2𝅧𝅩2𝅮𝅲2𝅻𝆂2𝆋𝆅2𝆪𝆭2𝉂𝉄2𝨀𝨶2𝨻𝩬1𝩵1𝪄2𝪛𝪟2𝪡𝪯2𞀀𞀆2𞀈𞀘2𞀛𞀡2𞀣𞀤2𞀦𞀪1𞂏2𞄰𞄶1𞊮2𞋬𞋯2𞓯𞓬2𞣐𞣖2𞥊𞥄2🏻🏿2󠀠󠁿2󠄀󠇯" -------------------------------------------------------------------------------- /src/String/Graphemes/Data/Extended_Pictographic.elm: -------------------------------------------------------------------------------- 1 | module String.Graphemes.Data.Extended_Pictographic exposing (chars, match) 2 | 3 | {-| Hey, this module was generated automatically. Please don't edit it. 4 | 5 | Run `make src/String/Graphemes/Data/Extended_Pictographic.elm` instead! 6 | 7 | -} 8 | 9 | import String.Graphemes.Data as Data 10 | import String.Graphemes.RangeDict as RangeDict exposing (RangeDict) 11 | import String.Graphemes.RangeDict.Range as Range exposing (Range) 12 | 13 | 14 | match : Char -> Bool 15 | match c = 16 | RangeDict.member c chars 17 | 18 | 19 | chars : RangeDict Char Data.Class 20 | chars = 21 | (Result.withDefault RangeDict.empty << Data.parser Data.ExtendedPictographic) 22 | "1©1®1‼1⁉1™1ℹ2↔↙2↩↪2⌚⌛1⌨1⎈1⏏2⏩⏬2⏭⏮1⏯1⏰2⏱⏲1⏳2⏸⏺1Ⓜ2▪▫1▶1◀2◻◾2☀☁2☂☃1☄1★2☇☍1☎2☏☐1☑1☒2☔☕2☖☗1☘2☙☜1☝2☞☟1☠1☡2☢☣2☤☥1☦2☧☩1☪2☫☭1☮1☯2☰☷2☸☹1☺2☻☿1♀1♁1♂2♃♇2♈♓2♔♞1♟1♠2♡♢1♣1♤2♥♦1♧1♨2♩♺1♻2♼♽1♾1♿2⚀⚅2⚐⚑1⚒1⚓1⚔1⚕2⚖⚗1⚘1⚙1⚚2⚛⚜2⚝⚟2⚠⚡2⚢⚦1⚧2⚨⚩2⚪⚫2⚬⚯2⚰⚱2⚲⚼2⚽⚾2⚿⛃2⛄⛅2⛆⛇1⛈2⛉⛍1⛎1⛏1⛐1⛑1⛒1⛓1⛔2⛕⛨1⛩1⛪2⛫⛯2⛰⛱2⛲⛳1⛴1⛵1⛶2⛷⛹1⛺2⛻⛼1⛽2⛾✁1✂2✃✄1✅2✈✌1✍1✎1✏2✐✑1✒1✔1✖1✝1✡1✨2✳✴1❄1❇1❌1❎2❓❕1❗1❣1❤2❥❧2➕➗1➡1➰1➿2⤴⤵2⬅⬇2⬛⬜1⭐1⭕1〰1〽1㊗1㊙2🀀🀃1🀄2🀅🃎1🃏2🃐🃿2🄍🄏1🄯2🅬🅯2🅰🅱2🅾🅿1🆎2🆑🆚2🆭🇥2🈁🈂2🈃🈏1🈚1🈯2🈲🈺2🈼🈿2🉉🉏2🉐🉑2🉒🋿2🌀🌌2🌍🌎1🌏1🌐1🌑1🌒2🌓🌕2🌖🌘1🌙1🌚1🌛1🌜2🌝🌞2🌟🌠1🌡2🌢🌣2🌤🌬2🌭🌯2🌰🌱2🌲🌳2🌴🌵1🌶2🌷🍊1🍋2🍌🍏1🍐2🍑🍻1🍼1🍽2🍾🍿2🎀🎓2🎔🎕2🎖🎗1🎘2🎙🎛2🎜🎝2🎞🎟2🎠🏄1🏅1🏆1🏇1🏈1🏉1🏊2🏋🏎2🏏🏓2🏔🏟2🏠🏣1🏤2🏥🏰2🏱🏲1🏳1🏴1🏵1🏶1🏷2🏸🏺2🐀🐇1🐈2🐉🐋2🐌🐎2🐏🐐2🐑🐒1🐓1🐔1🐕1🐖2🐗🐩1🐪2🐫🐾1🐿1👀1👁2👂👤1👥2👦👫2👬👭2👮💬1💭2💮💵2💶💷2💸📫2📬📭1📮1📯2📰📴1📵2📶📷1📸2📹📼1📽1📾2📿🔂1🔃2🔄🔇1🔈1🔉2🔊🔔1🔕2🔖🔫2🔬🔭2🔮🔽2🕆🕈2🕉🕊2🕋🕎1🕏2🕐🕛2🕜🕧2🕨🕮2🕯🕰2🕱🕲2🕳🕹1🕺2🕻🖆1🖇2🖈🖉2🖊🖍2🖎🖏1🖐2🖑🖔2🖕🖖2🖗🖣1🖤1🖥2🖦🖧1🖨2🖩🖰2🖱🖲2🖳🖻1🖼2🖽🗁2🗂🗄2🗅🗐2🗑🗓2🗔🗛2🗜🗞2🗟🗠1🗡1🗢1🗣2🗤🗧1🗨2🗩🗮1🗯2🗰🗲1🗳2🗴🗹1🗺2🗻🗿1😀2😁😆2😇😈2😉😍1😎1😏1😐1😑2😒😔1😕1😖1😗1😘1😙1😚1😛2😜😞1😟2😠😥2😦😧2😨😫1😬1😭2😮😯2😰😳1😴1😵1😶2😷🙀2🙁🙄2🙅🙏1🚀2🚁🚂2🚃🚅1🚆1🚇1🚈1🚉2🚊🚋1🚌1🚍1🚎1🚏1🚐2🚑🚓1🚔1🚕1🚖1🚗1🚘2🚙🚚2🚛🚡1🚢1🚣2🚤🚥1🚦2🚧🚭2🚮🚱1🚲2🚳🚵1🚶2🚷🚸2🚹🚾1🚿1🛀2🛁🛅2🛆🛊1🛋1🛌2🛍🛏1🛐2🛑🛒2🛓🛔1🛕2🛖🛗2🛘🛛1🛜2🛝🛟2🛠🛥2🛦🛨1🛩1🛪2🛫🛬2🛭🛯1🛰2🛱🛲1🛳2🛴🛶2🛷🛸1🛹1🛺2🛻🛼2🛽🛿2🝴🝿2🟕🟟2🟠🟫2🟬🟯1🟰2🟱🟿2🠌🠏2🡈🡏2🡚🡟2🢈🢏2🢮🣿1🤌2🤍🤏2🤐🤘2🤙🤞1🤟2🤠🤧2🤨🤯1🤰2🤱🤲2🤳🤺2🤼🤾1🤿2🥀🥅2🥇🥋1🥌2🥍🥏2🥐🥞2🥟🥫2🥬🥰1🥱1🥲2🥳🥶2🥷🥸1🥹1🥺1🥻2🥼🥿2🦀🦄2🦅🦑2🦒🦗2🦘🦢2🦣🦤2🦥🦪2🦫🦭2🦮🦯2🦰🦹2🦺🦿1🧀2🧁🧂2🧃🧊1🧋1🧌2🧍🧏2🧐🧦2🧧🧿2🨀🩯2🩰🩳1🩴2🩵🩷2🩸🩺2🩻🩼2🩽🩿2🪀🪂2🪃🪆2🪇🪈2🪉🪏2🪐🪕2🪖🪨2🪩🪬2🪭🪯2🪰🪶2🪷🪺2🪻🪽1🪾1🪿2🫀🫂2🫃🫅2🫆🫍2🫎🫏2🫐🫖2🫗🫙2🫚🫛2🫜🫟2🫠🫧1🫨2🫩🫯2🫰🫶2🫷🫸2🫹🫿2🰀🿽" -------------------------------------------------------------------------------- /src/String/Graphemes/Data/L.elm: -------------------------------------------------------------------------------- 1 | module String.Graphemes.Data.L exposing (chars, match) 2 | 3 | {-| Hey, this module was generated automatically. Please don't edit it. 4 | 5 | Run `make src/String/Graphemes/Data/L.elm` instead! 6 | 7 | -} 8 | 9 | import String.Graphemes.Data as Data 10 | import String.Graphemes.RangeDict as RangeDict exposing (RangeDict) 11 | import String.Graphemes.RangeDict.Range as Range exposing (Range) 12 | 13 | 14 | match : Char -> Bool 15 | match c = 16 | RangeDict.member c chars 17 | 18 | 19 | chars : RangeDict Char Data.Class 20 | chars = 21 | (Result.withDefault RangeDict.empty << Data.parser Data.L) 22 | "2ᄀᅟ2ꥠꥼ" -------------------------------------------------------------------------------- /src/String/Graphemes/Data/LF.elm: -------------------------------------------------------------------------------- 1 | module String.Graphemes.Data.LF exposing (chars, match) 2 | 3 | {-| Hey, this module was generated automatically. Please don't edit it. 4 | 5 | Run `make src/String/Graphemes/Data/LF.elm` instead! 6 | 7 | -} 8 | 9 | import String.Graphemes.Data as Data 10 | import String.Graphemes.RangeDict as RangeDict exposing (RangeDict) 11 | import String.Graphemes.RangeDict.Range as Range exposing (Range) 12 | 13 | 14 | match : Char -> Bool 15 | match c = 16 | RangeDict.member c chars 17 | 18 | 19 | chars : RangeDict Char Data.Class 20 | chars = 21 | (Result.withDefault RangeDict.empty << Data.parser Data.LF) 22 | "1\n" -------------------------------------------------------------------------------- /src/String/Graphemes/Data/LV.elm: -------------------------------------------------------------------------------- 1 | module String.Graphemes.Data.LV exposing (chars, match) 2 | 3 | {-| Hey, this module was generated automatically. Please don't edit it. 4 | 5 | Run `make src/String/Graphemes/Data/LV.elm` instead! 6 | 7 | -} 8 | 9 | import String.Graphemes.Data as Data 10 | import String.Graphemes.RangeDict as RangeDict exposing (RangeDict) 11 | import String.Graphemes.RangeDict.Range as Range exposing (Range) 12 | 13 | 14 | match : Char -> Bool 15 | match c = 16 | RangeDict.member c chars 17 | 18 | 19 | chars : RangeDict Char Data.Class 20 | chars = 21 | (Result.withDefault RangeDict.empty << Data.parser Data.LV) 22 | "1가1개1갸1걔1거1게1겨1계1고1과1괘1괴1교1구1궈1궤1귀1규1그1긔1기1까1깨1꺄1꺠1꺼1께1껴1꼐1꼬1꽈1꽤1꾀1꾜1꾸1꿔1꿰1뀌1뀨1끄1끠1끼1나1내1냐1냬1너1네1녀1녜1노1놔1놰1뇌1뇨1누1눠1눼1뉘1뉴1느1늬1니1다1대1댜1댸1더1데1뎌1뎨1도1돠1돼1되1됴1두1둬1뒈1뒤1듀1드1듸1디1따1때1땨1떄1떠1떼1뗘1뗴1또1똬1뙈1뙤1뚀1뚜1뚸1뛔1뛰1뜌1뜨1띄1띠1라1래1랴1럐1러1레1려1례1로1롸1뢔1뢰1료1루1뤄1뤠1뤼1류1르1릐1리1마1매1먀1먜1머1메1며1몌1모1뫄1뫠1뫼1묘1무1뭐1뭬1뮈1뮤1므1믜1미1바1배1뱌1뱨1버1베1벼1볘1보1봐1봬1뵈1뵤1부1붜1붸1뷔1뷰1브1븨1비1빠1빼1뺘1뺴1뻐1뻬1뼈1뼤1뽀1뽜1뽸1뾔1뾰1뿌1뿨1쀄1쀠1쀼1쁘1쁴1삐1사1새1샤1섀1서1세1셔1셰1소1솨1쇄1쇠1쇼1수1숴1쉐1쉬1슈1스1싀1시1싸1쌔1쌰1썌1써1쎄1쎠1쎼1쏘1쏴1쐐1쐬1쑈1쑤1쒀1쒜1쒸1쓔1쓰1씌1씨1아1애1야1얘1어1에1여1예1오1와1왜1외1요1우1워1웨1위1유1으1의1이1자1재1쟈1쟤1저1제1져1졔1조1좌1좨1죄1죠1주1줘1줴1쥐1쥬1즈1즤1지1짜1째1쨔1쨰1쩌1쩨1쪄1쪠1쪼1쫘1쫴1쬐1쬬1쭈1쭤1쮀1쮜1쮸1쯔1쯰1찌1차1채1챠1챼1처1체1쳐1쳬1초1촤1쵀1최1쵸1추1춰1췌1취1츄1츠1츼1치1카1캐1캬1컈1커1케1켜1켸1코1콰1쾌1쾨1쿄1쿠1쿼1퀘1퀴1큐1크1킈1키1타1태1탸1턔1터1테1텨1톄1토1톼1퇘1퇴1툐1투1퉈1퉤1튀1튜1트1틔1티1파1패1퍄1퍠1퍼1페1펴1폐1포1퐈1퐤1푀1표1푸1풔1풰1퓌1퓨1프1픠1피1하1해1햐1햬1허1헤1혀1혜1호1화1홰1회1효1후1훠1훼1휘1휴1흐1희1히" -------------------------------------------------------------------------------- /src/String/Graphemes/Data/LVT.elm: -------------------------------------------------------------------------------- 1 | module String.Graphemes.Data.LVT exposing (chars, match) 2 | 3 | {-| Hey, this module was generated automatically. Please don't edit it. 4 | 5 | Run `make src/String/Graphemes/Data/LVT.elm` instead! 6 | 7 | -} 8 | 9 | import String.Graphemes.Data as Data 10 | import String.Graphemes.RangeDict as RangeDict exposing (RangeDict) 11 | import String.Graphemes.RangeDict.Range as Range exposing (Range) 12 | 13 | 14 | match : Char -> Bool 15 | match c = 16 | RangeDict.member c chars 17 | 18 | 19 | chars : RangeDict Char Data.Class 20 | chars = 21 | (Result.withDefault RangeDict.empty << Data.parser Data.LVT) 22 | "2각갛2객갷2갹걓2걕걯2걱겋2겍겧2격곃2곅곟2곡곻2곽괗2괙괳2괵굏2굑굫2국궇2궉궣2궥궿2귁귛2귝귷2극긓2긕긯2긱깋2깍깧2깩꺃2꺅꺟2꺡꺻2꺽껗2껙껳2껵꼏2꼑꼫2꼭꽇2꽉꽣2꽥꽿2꾁꾛2꾝꾷2꾹꿓2꿕꿯2꿱뀋2뀍뀧2뀩끃2끅끟2끡끻2끽낗2낙낳2낵냏2냑냫2냭넇2넉넣2넥넿2녁녛2녝녷2녹놓2놕놯2놱뇋2뇍뇧2뇩눃2눅눟2눡눻2눽뉗2뉙뉳2뉵늏2늑늫2늭닇2닉닣2닥닿2댁댛2댝댷2댹덓2덕덯2덱뎋2뎍뎧2뎩돃2독돟2돡돻2돽됗2됙됳2됵둏2둑둫2둭뒇2뒉뒣2뒥뒿2듁듛2득듷2듹딓2딕딯2딱땋2땍땧2땩떃2떅떟2떡떻2떽뗗2뗙뗳2뗵똏2똑똫2똭뙇2뙉뙣2뙥뙿2뚁뚛2뚝뚷2뚹뛓2뛕뛯2뛱뜋2뜍뜧2뜩띃2띅띟2띡띻2락랗2랙랳2략럏2럑럫2럭렇2렉렣2력렿2롁롛2록롷2롹뢓2뢕뢯2뢱룋2룍룧2룩뤃2뤅뤟2뤡뤻2뤽륗2륙륳2륵릏2릑릫2릭맇2막맣2맥맿2먁먛2먝먷2먹멓2멕멯2멱몋2몍몧2목뫃2뫅뫟2뫡뫻2뫽묗2묙묳2묵뭏2뭑뭫2뭭뮇2뮉뮣2뮥뮿2믁믛2믝믷2믹밓2박밯2백뱋2뱍뱧2뱩벃2벅벟2벡벻2벽볗2볙볳2복봏2봑봫2봭뵇2뵉뵣2뵥뵿2북붛2붝붷2붹뷓2뷕뷯2뷱븋2븍븧2븩빃2빅빟2빡빻2빽뺗2뺙뺳2뺵뻏2뻑뻫2뻭뼇2뼉뼣2뼥뼿2뽁뽛2뽝뽷2뽹뾓2뾕뾯2뾱뿋2뿍뿧2뿩쀃2쀅쀟2쀡쀻2쀽쁗2쁙쁳2쁵삏2삑삫2삭샇2색샣2샥샿2섁섛2석섷2섹셓2셕셯2셱솋2속솧2솩쇃2쇅쇟2쇡쇻2쇽숗2숙숳2숵쉏2쉑쉫2쉭슇2슉슣2슥슿2싁싛2식싷2싹쌓2쌕쌯2쌱썋2썍썧2썩쎃2쎅쎟2쎡쎻2쎽쏗2쏙쏳2쏵쐏2쐑쐫2쐭쑇2쑉쑣2쑥쑿2쒁쒛2쒝쒷2쒹쓓2쓕쓯2쓱씋2씍씧2씩앃2악앟2액앻2약얗2얙얳2억엏2엑엫2역옇2옉옣2옥옿2왁왛2왝왷2왹욓2욕욯2욱웋2웍웧2웩윃2윅윟2육윻2윽읗2읙읳2익잏2작잫2잭쟇2쟉쟣2쟥쟿2적젛2젝젷2젹졓2졕졯2족좋2좍좧2좩죃2죅죟2죡죻2죽줗2줙줳2줵쥏2쥑쥫2쥭즇2즉즣2즥즿2직짛2짝짷2짹쨓2쨕쨯2쨱쩋2쩍쩧2쩩쪃2쪅쪟2쪡쪻2쪽쫗2쫙쫳2쫵쬏2쬑쬫2쬭쭇2쭉쭣2쭥쭿2쮁쮛2쮝쮷2쮹쯓2쯕쯯2쯱찋2찍찧2착챃2책챟2챡챻2챽첗2척첳2첵쳏2쳑쳫2쳭촇2촉촣2촥촿2쵁쵛2쵝쵷2쵹춓2축춯2춱췋2췍췧2췩츃2츅츟2측츻2츽칗2칙칳2칵캏2캑캫2캭컇2컉컣2컥컿2켁켛2켝켷2켹콓2콕콯2콱쾋2쾍쾧2쾩쿃2쿅쿟2쿡쿻2쿽퀗2퀙퀳2퀵큏2큑큫2큭킇2킉킣2킥킿2탁탛2택탷2탹턓2턕턯2턱텋2텍텧2텩톃2톅톟2톡톻2톽퇗2퇙퇳2퇵툏2툑툫2툭퉇2퉉퉣2퉥퉿2튁튛2튝튷2특틓2틕틯2틱팋2팍팧2팩퍃2퍅퍟2퍡퍻2퍽펗2펙펳2펵폏2폑폫2폭퐇2퐉퐣2퐥퐿2푁푛2푝푷2푹풓2풕풯2풱퓋2퓍퓧2퓩픃2픅픟2픡픻2픽핗2학핳2핵햏2햑햫2햭헇2헉헣2헥헿2혁혛2혝혷2혹홓2확홯2홱횋2획횧2횩훃2훅훟2훡훻2훽휗2휙휳2휵흏2흑흫2흭힇2힉힣" -------------------------------------------------------------------------------- /src/String/Graphemes/Data/Prepend.elm: -------------------------------------------------------------------------------- 1 | module String.Graphemes.Data.Prepend exposing (chars, match) 2 | 3 | {-| Hey, this module was generated automatically. Please don't edit it. 4 | 5 | Run `make src/String/Graphemes/Data/Prepend.elm` instead! 6 | 7 | -} 8 | 9 | import String.Graphemes.Data as Data 10 | import String.Graphemes.RangeDict as RangeDict exposing (RangeDict) 11 | import String.Graphemes.RangeDict.Range as Range exposing (Range) 12 | 13 | 14 | match : Char -> Bool 15 | match c = 16 | RangeDict.member c chars 17 | 18 | 19 | chars : RangeDict Char Data.Class 20 | chars = 21 | (Result.withDefault RangeDict.empty << Data.parser Data.Prepend) 22 | "2؀؅1۝1܏2࢐࢑1࣢1ൎ1𑂽1𑃍2𑇂𑇃1𑤿1𑥁1𑨺2𑪄𑪉1𑵆1𑼂" -------------------------------------------------------------------------------- /src/String/Graphemes/Data/Regional_Indicator.elm: -------------------------------------------------------------------------------- 1 | module String.Graphemes.Data.Regional_Indicator exposing (chars, match) 2 | 3 | {-| Hey, this module was generated automatically. Please don't edit it. 4 | 5 | Run `make src/String/Graphemes/Data/Regional_Indicator.elm` instead! 6 | 7 | -} 8 | 9 | import String.Graphemes.Data as Data 10 | import String.Graphemes.RangeDict as RangeDict exposing (RangeDict) 11 | import String.Graphemes.RangeDict.Range as Range exposing (Range) 12 | 13 | 14 | match : Char -> Bool 15 | match c = 16 | RangeDict.member c chars 17 | 18 | 19 | chars : RangeDict Char Data.Class 20 | chars = 21 | (Result.withDefault RangeDict.empty << Data.parser Data.RegionalIndicator) 22 | "2🇦🇿" -------------------------------------------------------------------------------- /src/String/Graphemes/Data/SpacingMark.elm: -------------------------------------------------------------------------------- 1 | module String.Graphemes.Data.SpacingMark exposing (chars, match) 2 | 3 | {-| Hey, this module was generated automatically. Please don't edit it. 4 | 5 | Run `make src/String/Graphemes/Data/SpacingMark.elm` instead! 6 | 7 | -} 8 | 9 | import String.Graphemes.Data as Data 10 | import String.Graphemes.RangeDict as RangeDict exposing (RangeDict) 11 | import String.Graphemes.RangeDict.Range as Range exposing (Range) 12 | 13 | 14 | match : Char -> Bool 15 | match c = 16 | RangeDict.member c chars 17 | 18 | 19 | chars : RangeDict Char Data.Class 20 | chars = 21 | (Result.withDefault RangeDict.empty << Data.parser Data.SpacingMark) 22 | "1ः1ऻ2ाी2ॉौ2ॎॏ2ংঃ2িী2েৈ2োৌ1ਃ2ਾੀ1ઃ2ાી1ૉ2ોૌ2ଂଃ1ୀ2େୈ2ୋୌ1ி2ுூ2ெை2ொௌ2ఁః2ుౄ2ಂಃ1ಾ2ೀು2ೃೄ2ೇೈ2ೊೋ1ೳ2ംഃ2ിീ2െൈ2ൊൌ2ංඃ2ැෑ2ෘෞ2ෲෳ1ำ1ຳ2༾༿1ཿ1ေ2ျြ2ၖၗ1ႄ1᜕1᜴1ា2ើៅ2ះៈ2ᤣᤦ2ᤩᤫ2ᤰᤱ2ᤳᤸ2ᨙᨚ1ᩕ1ᩗ2ᩭᩲ1ᬄ1ᬻ2ᬽᭁ2ᭃ᭄1ᮂ1ᮡ2ᮦᮧ1᮪1ᯧ2ᯪᯬ1ᯮ2᯲᯳2ᰤᰫ2ᰴᰵ1᳡1᳷2ꠣꠤ1ꠧ2ꢀꢁ2ꢴꣃ2ꥒ꥓1ꦃ2ꦴꦵ2ꦺꦻ2ꦾ꧀2ꨯꨰ2ꨳꨴ1ꩍ1ꫫ2ꫮꫯ1ꫵ2ꯣꯤ2ꯦꯧ2ꯩꯪ1꯬1𑀀1𑀂1𑂂2𑂰𑂲2𑂷𑂸1𑄬2𑅅𑅆1𑆂2𑆳𑆵2𑆿𑇀1𑇎2𑈬𑈮2𑈲𑈳1𑈵2𑋠𑋢2𑌂𑌃1𑌿2𑍁𑍄2𑍇𑍈2𑍋𑍍2𑍢𑍣2𑐵𑐷2𑑀𑑁1𑑅2𑒱𑒲1𑒹2𑒻𑒼1𑒾1𑓁2𑖰𑖱2𑖸𑖻1𑖾2𑘰𑘲2𑘻𑘼1𑘾1𑚬2𑚮𑚯1𑚶1𑜦2𑠬𑠮1𑠸2𑤱𑤵2𑤷𑤸1𑤽1𑥀1𑥂2𑧑𑧓2𑧜𑧟1𑧤1𑨹2𑩗𑩘1𑪗1𑰯1𑰾1𑲩1𑲱1𑲴2𑶊𑶎2𑶓𑶔1𑶖2𑻵𑻶1𑼃2𑼴𑼵2𑼾𑼿1𑽁2𖽑𖾇2𖿰𖿱1𝅦1𝅭" -------------------------------------------------------------------------------- /src/String/Graphemes/Data/T.elm: -------------------------------------------------------------------------------- 1 | module String.Graphemes.Data.T exposing (chars, match) 2 | 3 | {-| Hey, this module was generated automatically. Please don't edit it. 4 | 5 | Run `make src/String/Graphemes/Data/T.elm` instead! 6 | 7 | -} 8 | 9 | import String.Graphemes.Data as Data 10 | import String.Graphemes.RangeDict as RangeDict exposing (RangeDict) 11 | import String.Graphemes.RangeDict.Range as Range exposing (Range) 12 | 13 | 14 | match : Char -> Bool 15 | match c = 16 | RangeDict.member c chars 17 | 18 | 19 | chars : RangeDict Char Data.Class 20 | chars = 21 | (Result.withDefault RangeDict.empty << Data.parser Data.T) 22 | "2ᆨᇿ2ퟋퟻ" -------------------------------------------------------------------------------- /src/String/Graphemes/Data/V.elm: -------------------------------------------------------------------------------- 1 | module String.Graphemes.Data.V exposing (chars, match) 2 | 3 | {-| Hey, this module was generated automatically. Please don't edit it. 4 | 5 | Run `make src/String/Graphemes/Data/V.elm` instead! 6 | 7 | -} 8 | 9 | import String.Graphemes.Data as Data 10 | import String.Graphemes.RangeDict as RangeDict exposing (RangeDict) 11 | import String.Graphemes.RangeDict.Range as Range exposing (Range) 12 | 13 | 14 | match : Char -> Bool 15 | match c = 16 | RangeDict.member c chars 17 | 18 | 19 | chars : RangeDict Char Data.Class 20 | chars = 21 | (Result.withDefault RangeDict.empty << Data.parser Data.V) 22 | "2ᅠᆧ2ힰퟆ" -------------------------------------------------------------------------------- /src/String/Graphemes/Data/ZWJ.elm: -------------------------------------------------------------------------------- 1 | module String.Graphemes.Data.ZWJ exposing (chars, match) 2 | 3 | {-| Hey, this module was generated automatically. Please don't edit it. 4 | 5 | Run `make src/String/Graphemes/Data/ZWJ.elm` instead! 6 | 7 | -} 8 | 9 | import String.Graphemes.Data as Data 10 | import String.Graphemes.RangeDict as RangeDict exposing (RangeDict) 11 | import String.Graphemes.RangeDict.Range as Range exposing (Range) 12 | 13 | 14 | match : Char -> Bool 15 | match c = 16 | RangeDict.member c chars 17 | 18 | 19 | chars : RangeDict Char Data.Class 20 | chars = 21 | (Result.withDefault RangeDict.empty << Data.parser Data.ZWJ) 22 | "1‍" -------------------------------------------------------------------------------- /src/String/Graphemes/Parser.elm: -------------------------------------------------------------------------------- 1 | module String.Graphemes.Parser exposing (foldl, uncons) 2 | 3 | import String.Graphemes.Data as Data exposing (Class(..)) 4 | import String.Graphemes.Data.CR as CR 5 | import String.Graphemes.Data.Control as Control 6 | import String.Graphemes.Data.Extend as Extend 7 | import String.Graphemes.Data.Extended_Pictographic as ExtendedPictographic 8 | import String.Graphemes.Data.L as L 9 | import String.Graphemes.Data.LF as LF 10 | import String.Graphemes.Data.LV as LV 11 | import String.Graphemes.Data.LVT as LVT 12 | import String.Graphemes.Data.Prepend as Prepend 13 | import String.Graphemes.Data.Regional_Indicator as RegionalIndicator 14 | import String.Graphemes.Data.SpacingMark as SpacingMark 15 | import String.Graphemes.Data.T as T 16 | import String.Graphemes.Data.V as V 17 | import String.Graphemes.Data.ZWJ as ZWJ 18 | import String.Graphemes.RangeDict as RangeDict exposing (RangeDict) 19 | 20 | 21 | foldl : (String -> a -> a) -> a -> String -> a 22 | foldl fn initial string = 23 | case string of 24 | "" -> 25 | initial 26 | 27 | _ -> 28 | let 29 | ( chars, remaining ) = 30 | unconsHelp string [] 31 | in 32 | foldl fn (fn (String.fromList (List.reverse chars)) initial) remaining 33 | 34 | uncons : String -> Maybe ( String, String ) 35 | uncons string = 36 | case string of 37 | "" -> 38 | Nothing 39 | 40 | _ -> 41 | let 42 | ( chars, remaining ) = 43 | unconsHelp string [] 44 | in 45 | Just ( String.fromList (List.reverse chars), remaining ) 46 | 47 | 48 | unconsHelp : String -> List Char -> ( List Char, String ) 49 | unconsHelp str chars = 50 | case ( String.uncons str, chars ) of 51 | ( Nothing, [] ) -> 52 | -- `String.uncons` returns `Nothing` when the first character is a 53 | -- null byte. See https://github.com/elm/core/issues/1035. 54 | if String.left 1 str == "\u{0000}" then 55 | unconsHelp (String.dropLeft 1 str) [ '\u{0000}' ] 56 | 57 | else 58 | ( chars, "" ) 59 | 60 | ( Nothing, last :: rest ) -> 61 | -- `String.uncons` returns `Nothing` when the first character is a 62 | -- null byte. See https://github.com/elm/core/issues/1035. 63 | if String.left 1 str == "\u{0000}" then 64 | if shouldBreakBefore last rest '\u{0000}' then 65 | ( chars, str ) 66 | 67 | else 68 | unconsHelp (String.dropLeft 1 str) ('\u{0000}' :: chars) 69 | 70 | else 71 | ( chars, "" ) 72 | 73 | ( Just ( char, strTail ), [] ) -> 74 | unconsHelp strTail [ char ] 75 | 76 | ( Just ( char, strTail ), last :: rest ) -> 77 | if shouldBreakBefore last rest char then 78 | ( chars, str ) 79 | 80 | else 81 | unconsHelp strTail (char :: chars) 82 | 83 | 84 | shouldBreakBefore : Char -> List Char -> Char -> Bool 85 | shouldBreakBefore lastChar restChars nextChar = 86 | case 87 | ( RangeDict.get lastChar classes 88 | , RangeDict.get nextChar classes 89 | ) 90 | of 91 | -- CR only extends for CRLF 92 | ( Just CR, Just LF ) -> 93 | False 94 | 95 | ( Just CR, _ ) -> 96 | True 97 | 98 | -- LF always breaks 99 | ( Just LF, _ ) -> 100 | True 101 | 102 | -- Control always breaks 103 | ( Just Control, _ ) -> 104 | True 105 | 106 | -- regional indicators form sequences of exactly two 107 | ( Just RegionalIndicator, Just RegionalIndicator ) -> 108 | not (List.isEmpty restChars) 109 | 110 | -- prepend only breaks for CR, LF, and Control 111 | ( Just Prepend, Just CR ) -> 112 | True 113 | 114 | ( Just Prepend, Just LF ) -> 115 | True 116 | 117 | ( Just Prepend, Just Control ) -> 118 | True 119 | 120 | ( Just Prepend, _ ) -> 121 | False 122 | 123 | -- Hangul L 124 | ( Just L, Just L ) -> 125 | False 126 | 127 | ( Just L, Just V ) -> 128 | False 129 | 130 | ( Just L, Just LV ) -> 131 | False 132 | 133 | ( Just L, Just LVT ) -> 134 | False 135 | 136 | -- Hangul V 137 | ( Just V, Just V ) -> 138 | False 139 | 140 | ( Just V, Just T ) -> 141 | False 142 | 143 | -- Hangul T 144 | ( Just T, Just T ) -> 145 | False 146 | 147 | -- Hangul LV 148 | ( Just LV, Just V ) -> 149 | False 150 | 151 | ( Just LV, Just T ) -> 152 | False 153 | 154 | -- Hangul LVT 155 | ( Just LVT, Just T ) -> 156 | False 157 | 158 | -- Emoji modification sequences 159 | ( Just ZWJ, Just ExtendedPictographic ) -> 160 | restChars 161 | |> List.map (\c -> RangeDict.get c classes) 162 | |> shouldBreakForRule11 163 | 164 | -- other than special cases handled above, everything breaks on ZWJ, 165 | -- SpacingMark, and Extend 166 | ( _, Just ZWJ ) -> 167 | False 168 | 169 | ( _, Just SpacingMark ) -> 170 | False 171 | 172 | ( _, Just Extend ) -> 173 | False 174 | 175 | _ -> 176 | True 177 | 178 | 179 | {-| Rule 11 looks like this: `ExtPict Extend* ZWJ ExtPict` 180 | 181 | We already handle the terminal ZWJ and ExtPict above, so we just need to deal 182 | with the list of Extend and the initial ExtPict. 183 | 184 | -} 185 | shouldBreakForRule11 : List (Maybe Class) -> Bool 186 | shouldBreakForRule11 classes_ = 187 | case classes_ of 188 | (Just Extend) :: rest -> 189 | shouldBreakForRule11 rest 190 | 191 | [ Just ExtendedPictographic ] -> 192 | False 193 | 194 | _ -> 195 | True 196 | 197 | 198 | classes : RangeDict Char Data.Class 199 | classes = 200 | List.foldl 201 | RangeDict.union 202 | RangeDict.empty 203 | [ CR.chars 204 | , LF.chars 205 | , Control.chars 206 | , Extend.chars 207 | , RegionalIndicator.chars 208 | , Prepend.chars 209 | , SpacingMark.chars 210 | , L.chars 211 | , V.chars 212 | , T.chars 213 | , LV.chars 214 | , LVT.chars 215 | , ExtendedPictographic.chars 216 | , ZWJ.chars 217 | ] 218 | -------------------------------------------------------------------------------- /src/String/Graphemes/RangeDict.elm: -------------------------------------------------------------------------------- 1 | module String.Graphemes.RangeDict exposing (RangeDict, empty, fromList, get, getClosestRange, insert, lowerBound, member, toList, union, upperBound) 2 | 3 | import String.Graphemes.RangeDict.Range as Range exposing (Range) 4 | 5 | 6 | {-| Longer-term, this may make sense to release as a separate package. 7 | -} 8 | type RangeDict comparable value 9 | = Branch Int (Range comparable) value (RangeDict comparable value) (RangeDict comparable value) 10 | | Empty 11 | 12 | 13 | empty : RangeDict comparable value 14 | empty = 15 | Empty 16 | 17 | 18 | branch : Range comparable -> value -> RangeDict comparable value -> RangeDict comparable value -> RangeDict comparable value 19 | branch range value lt gt = 20 | Branch (max (height lt) (height gt) + 1) range value lt gt 21 | 22 | 23 | fromList : List ( Range comparable, value ) -> RangeDict comparable value 24 | fromList = 25 | List.foldl (\( range, value ) -> insert range value) Empty 26 | 27 | 28 | toList : RangeDict comparable value -> List ( Range comparable, value ) 29 | toList rangeDict = 30 | case rangeDict of 31 | Empty -> 32 | [] 33 | 34 | Branch _ here value lt gt -> 35 | toList lt ++ (( here, value ) :: toList gt) 36 | 37 | 38 | {-| combine two RangeDicts. The first value's ranges take precedence. 39 | -} 40 | union : RangeDict comparable value -> RangeDict comparable value -> RangeDict comparable value 41 | union a b = 42 | List.foldl (\( range_, value ) -> insert range_ value) b (toList a) 43 | 44 | 45 | insert : Range comparable -> value -> RangeDict comparable value -> RangeDict comparable value 46 | insert range value set = 47 | -- TODO: removing overlaps (but it doesn't matter a lot for our use case) 48 | case set of 49 | Empty -> 50 | branch range value Empty Empty 51 | 52 | Branch height_ here hereValue lt gt -> 53 | case Range.compare here range of 54 | Range.LT -> 55 | branch here hereValue (insert range value lt) gt |> balance 56 | 57 | Range.GT -> 58 | branch here hereValue lt (insert range value gt) |> balance 59 | 60 | Range.EQ -> 61 | set 62 | 63 | Range.Overlapping -> 64 | let 65 | combined = 66 | Range.combine range here 67 | in 68 | -- TODO: this is no longer good enough now that this is a 69 | -- key/value store. We need to be very precise about the 70 | -- parts of the range we're storing. 71 | branch combined value lt gt 72 | 73 | 74 | get : comparable -> RangeDict comparable value -> Maybe value 75 | get what rangeDict = 76 | getHelp (Range.point what) rangeDict 77 | 78 | 79 | getHelp : Range comparable -> RangeDict comparable value -> Maybe value 80 | getHelp range rangeDict = 81 | case rangeDict of 82 | Empty -> 83 | Nothing 84 | 85 | Branch height_ here value lt gt -> 86 | case Range.compare range here of 87 | Range.LT -> 88 | getHelp range gt 89 | 90 | Range.GT -> 91 | getHelp range lt 92 | 93 | Range.EQ -> 94 | Just value 95 | 96 | Range.Overlapping -> 97 | Just value 98 | 99 | 100 | member : comparable -> RangeDict comparable value -> Bool 101 | member what rangeDict = 102 | case get what rangeDict of 103 | Nothing -> 104 | False 105 | 106 | Just _ -> 107 | True 108 | 109 | 110 | getClosestRange : comparable -> RangeDict comparable value -> Maybe (Range comparable) 111 | getClosestRange what rangeDict = 112 | getClosestRangeHelp (Range.point what) rangeDict 113 | 114 | 115 | getClosestRangeHelp : Range comparable -> RangeDict comparable value -> Maybe (Range comparable) 116 | getClosestRangeHelp range rangeDict = 117 | case rangeDict of 118 | Empty -> 119 | Nothing 120 | 121 | Branch _ here _ lt gt -> 122 | case Range.compare range here of 123 | Range.LT -> 124 | if lt == Empty then 125 | Just here 126 | 127 | else 128 | getClosestRangeHelp range lt 129 | 130 | Range.GT -> 131 | if gt == Empty then 132 | Just here 133 | 134 | else 135 | getClosestRangeHelp range gt 136 | 137 | Range.EQ -> 138 | Just here 139 | 140 | Range.Overlapping -> 141 | Just here 142 | 143 | 144 | lowerBound : RangeDict comparable value -> Maybe comparable 145 | lowerBound rangeDict = 146 | case rangeDict of 147 | Empty -> 148 | Nothing 149 | 150 | Branch _ here _ _ Empty -> 151 | Just (Range.lowerBound here) 152 | 153 | Branch _ _ _ _ lt -> 154 | lowerBound lt 155 | 156 | 157 | upperBound : RangeDict comparable value -> Maybe comparable 158 | upperBound rangeDict = 159 | case rangeDict of 160 | Empty -> 161 | Nothing 162 | 163 | Branch _ here _ Empty _ -> 164 | Just (Range.upperBound here) 165 | 166 | Branch _ _ _ gt _ -> 167 | upperBound gt 168 | 169 | 170 | balance : RangeDict comparable value -> RangeDict comparable value 171 | balance rangeDict = 172 | case rangeDict of 173 | Empty -> 174 | rangeDict 175 | 176 | Branch _ here value lt gt -> 177 | if heightDiff rangeDict == -2 && heightDiff lt == 1 then 178 | -- left leaning branch with right-leaning left subtree. 179 | branch here value (rotateLeft lt) gt |> rotateRight 180 | 181 | else if heightDiff rangeDict < -1 then 182 | rotateRight rangeDict 183 | 184 | else if heightDiff rangeDict == 2 && heightDiff gt == -1 then 185 | -- right leaning branch with left-leaning right subtree. 186 | branch here value lt (rotateRight gt) |> rotateLeft 187 | 188 | else if heightDiff rangeDict > 1 then 189 | rotateLeft rangeDict 190 | 191 | else 192 | rangeDict 193 | 194 | 195 | height : RangeDict comparable value -> Int 196 | height rangeDict = 197 | case rangeDict of 198 | Empty -> 199 | 0 200 | 201 | Branch height_ _ _ _ _ -> 202 | height_ 203 | 204 | 205 | heightDiff : RangeDict comparable value -> Int 206 | heightDiff rangeDict = 207 | case rangeDict of 208 | Empty -> 209 | 0 210 | 211 | Branch _ _ _ lt gt -> 212 | height gt - height lt 213 | 214 | 215 | rotateLeft : RangeDict comparable value -> RangeDict comparable value 216 | rotateLeft rangeDict = 217 | case rangeDict of 218 | Branch _ head value lessThans (Branch _ subHead subValue betweens greaterThans) -> 219 | branch subHead subValue (branch head value lessThans betweens) greaterThans 220 | 221 | _ -> 222 | rangeDict 223 | 224 | 225 | rotateRight : RangeDict comparable value -> RangeDict comparable value 226 | rotateRight rangeDict = 227 | case rangeDict of 228 | Branch _ head value (Branch _ subHead subValue lessThans betweens) greaterThans -> 229 | branch subHead subValue lessThans (branch head value betweens greaterThans) 230 | 231 | _ -> 232 | rangeDict 233 | -------------------------------------------------------------------------------- /src/String/Graphemes/RangeDict/Range.elm: -------------------------------------------------------------------------------- 1 | module String.Graphemes.RangeDict.Range exposing (Order(..), Range, combine, compare, lowerBound, point, range, upperBound) 2 | 3 | 4 | type Range comparable 5 | = Point comparable 6 | | Range comparable comparable 7 | 8 | 9 | point : comparable -> Range comparable 10 | point = 11 | Point 12 | 13 | 14 | range : comparable -> comparable -> Range comparable 15 | range a b = 16 | if a == b then 17 | Point a 18 | 19 | else 20 | Range (min a b) (max a b) 21 | 22 | 23 | lowerBound : Range comparable -> comparable 24 | lowerBound range_ = 25 | case range_ of 26 | Point x -> 27 | x 28 | 29 | Range low _ -> 30 | low 31 | 32 | 33 | upperBound : Range comparable -> comparable 34 | upperBound range_ = 35 | case range_ of 36 | Point x -> 37 | x 38 | 39 | Range _ high -> 40 | high 41 | 42 | 43 | type Order 44 | = EQ 45 | | GT 46 | | LT 47 | | Overlapping 48 | 49 | 50 | compare : Range comparable -> Range comparable -> Order 51 | compare a b = 52 | case ( a, b ) of 53 | ( Point x, Point y ) -> 54 | if x > y then 55 | GT 56 | 57 | else if x < y then 58 | LT 59 | 60 | else 61 | EQ 62 | 63 | ( Point x, Range low high ) -> 64 | if x < low then 65 | LT 66 | 67 | else if x > high then 68 | GT 69 | 70 | else 71 | Overlapping 72 | 73 | ( Range low high, Point x ) -> 74 | if x < low then 75 | GT 76 | 77 | else if x > high then 78 | LT 79 | 80 | else 81 | Overlapping 82 | 83 | ( Range low1 high1, Range low2 high2 ) -> 84 | if high1 < low2 then 85 | LT 86 | 87 | else if low1 > high2 then 88 | GT 89 | 90 | else if low1 == low2 && high1 == high2 then 91 | EQ 92 | 93 | else 94 | Overlapping 95 | 96 | 97 | combine : Range comparable -> Range comparable -> Range comparable 98 | combine a b = 99 | case ( a, b ) of 100 | ( Point x, Point y ) -> 101 | range x y 102 | 103 | ( Point x, Range low high ) -> 104 | Range (min x low) (max x high) 105 | 106 | ( Range low high, Point x ) -> 107 | Range (min x low) (max x high) 108 | 109 | ( Range low1 high1, Range low2 high2 ) -> 110 | Range (min low1 low2) (max high1 high2) 111 | -------------------------------------------------------------------------------- /tests/.dir-locals.el: -------------------------------------------------------------------------------- 1 | ((elm-mode (flycheck-elm-executable . "elm-test"))) 2 | -------------------------------------------------------------------------------- /tests/RangeDictFuzzer.elm: -------------------------------------------------------------------------------- 1 | module RangeDictFuzzer exposing (fromChars) 2 | 3 | import Fuzz exposing (Fuzzer) 4 | import String.Graphemes.RangeDict as RangeDict exposing (RangeDict) 5 | import String.Graphemes.RangeDict.Range as Range 6 | 7 | 8 | fromChars : RangeDict Char a -> Fuzzer String 9 | fromChars chars = 10 | case ( RangeDict.lowerBound chars, RangeDict.upperBound chars ) of 11 | ( Just lower, Just upper ) -> 12 | Fuzz.intRange (Char.toCode lower) (Char.toCode upper) 13 | |> Fuzz.map Char.fromCode 14 | |> Fuzz.map 15 | (\charMaybeOutOfRange -> 16 | if RangeDict.member charMaybeOutOfRange chars then 17 | charMaybeOutOfRange 18 | 19 | else 20 | case RangeDict.getClosestRange charMaybeOutOfRange chars of 21 | Just range -> 22 | Range.lowerBound range 23 | 24 | _ -> 25 | lower 26 | ) 27 | |> Fuzz.map String.fromChar 28 | 29 | _ -> 30 | Fuzz.invalid "the provided RangeDict did not have a lower or upper range (was it empty?)" 31 | -------------------------------------------------------------------------------- /tests/String/Graphemes/DataSpec.elm: -------------------------------------------------------------------------------- 1 | module String.Graphemes.DataSpec exposing (spec) 2 | 3 | import Expect 4 | import Fuzz exposing (Fuzzer, list) 5 | import String.Graphemes.Data as Data 6 | import String.Graphemes.RangeDict as RangeDict 7 | import String.Graphemes.RangeDict.Range as Range exposing (Range) 8 | import Test exposing (..) 9 | 10 | 11 | spec : Test 12 | spec = 13 | fuzz (shortList encoded) "parses the format correctly" <| 14 | \pairs -> 15 | let 16 | input = 17 | pairs 18 | |> List.map Tuple.second 19 | |> String.join "" 20 | 21 | output = 22 | pairs 23 | |> List.map (Tuple.mapSecond (always Data.Extend)) 24 | |> RangeDict.fromList 25 | in 26 | input 27 | |> Data.parser Data.Extend 28 | |> Expect.equal (Ok output) 29 | 30 | 31 | encoded : Fuzzer ( Range Char, String ) 32 | encoded = 33 | Fuzz.map2 34 | (\a b -> 35 | ( Range.range 36 | (Char.fromCode a) 37 | (Char.fromCode b) 38 | , if a == b then 39 | String.fromList [ '1', Char.fromCode a ] 40 | 41 | else 42 | String.fromList [ '2', Char.fromCode (min a b), Char.fromCode (max a b) ] 43 | ) 44 | ) 45 | (Fuzz.intRange 0 10000) 46 | (Fuzz.intRange 0 10000) 47 | 48 | 49 | shortList : Fuzzer a -> Fuzzer (List a) 50 | shortList fuzzer = 51 | Fuzz.oneOf 52 | [ Fuzz.constant [] 53 | , Fuzz.map List.singleton fuzzer 54 | , Fuzz.map2 (\a b -> [ a, b ]) fuzzer fuzzer 55 | ] 56 | -------------------------------------------------------------------------------- /tests/String/Graphemes/ParserSpec.elm: -------------------------------------------------------------------------------- 1 | module String.Graphemes.ParserSpec exposing (foldlSpec) 2 | 3 | import Expect exposing (Expectation) 4 | import Fuzz exposing (Fuzzer, list, oneOf) 5 | import RangeDictFuzzer 6 | import String.Graphemes.Data.CR as CR 7 | import String.Graphemes.Data.Control as Control 8 | import String.Graphemes.Data.Extend as Extend 9 | import String.Graphemes.Data.Extended_Pictographic as ExtendedPictographic 10 | import String.Graphemes.Data.L as L 11 | import String.Graphemes.Data.LF as LF 12 | import String.Graphemes.Data.LV as LV 13 | import String.Graphemes.Data.LVT as LVT 14 | import String.Graphemes.Data.Prepend as Prepend 15 | import String.Graphemes.Data.Regional_Indicator as RegionalIndicator 16 | import String.Graphemes.Data.SpacingMark as SpacingMark 17 | import String.Graphemes.Data.T as T 18 | import String.Graphemes.Data.V as V 19 | import String.Graphemes.Data.ZWJ as ZWJ 20 | import String.Graphemes.Parser as Parser 21 | import Test exposing (..) 22 | 23 | 24 | toList : String -> List String 25 | toList = 26 | Parser.foldl (::) [] >> List.reverse 27 | 28 | 29 | foldlSpec : Test 30 | foldlSpec = 31 | describe "graphemes" 32 | [ describe "real world strings" 33 | [ test "Hangul 'bumblebee' is parsed properly" <| 34 | \_ -> 35 | "꿀벌" 36 | |> toList 37 | |> Expect.equal [ "꿀", "벌" ] 38 | , test "real-world Hangul is parsed properly" <| 39 | \_ -> 40 | -- https://stqpkiraradongjae.bandcamp.com/album/sarah 41 | "당신이 키라라의 훌륭함을 잘 모르겠다면 문제는 당신에게 있다" 42 | |> toList 43 | |> Expect.equal [ "당", "신", "이", " ", "키", "라", "라", "의", " ", "훌", "륭", "함", "을", " ", "잘", " ", "모", "르", "겠", "다", "면", " ", "문", "제", "는", " ", "당", "신", "에", "게", " ", "있", "다" ] 44 | , test "skin tone and gender modifiers on emoji" <| 45 | \_ -> 46 | "🦸🏽\u{200D}♂️" 47 | |> toList 48 | |> Expect.equal [ "🦸🏽\u{200D}♂️" ] 49 | , test "zalgo, sure, why not" <| 50 | \_ -> 51 | -- some editors do not render this correctly. It should be 52 | -- the word "zalgo" with a bunch of diacritics above and 53 | -- below. Vim does this properly, the browser does too. 54 | "z̴̙͒ả̴̫̼̫̀̅ĺ̴̔̿͜g̷̨͇͉̊͐̚o̶̳̣̯͌̓" 55 | |> toList 56 | |> Expect.equal 57 | [ "z̴̙͒" 58 | , "ả̴̫̼̫̀̅" 59 | , "ĺ̴̔̿͜" 60 | , "g̷̨͇͉̊͐̚" 61 | , "o̶̳̣̯͌̓" 62 | ] 63 | ] 64 | , describe "2-character combinations" 65 | [ describeFollowing "carriage return" 66 | crCharacter 67 | { breakForEverything 68 | | lf = NoBreak 69 | } 70 | , describeFollowing "line feed" 71 | lfCharacter 72 | breakForEverything 73 | , describeFollowing "control character" 74 | controlCharacter 75 | breakForEverything 76 | , describeFollowing "extend character" 77 | extendCharacter 78 | { breakForEverything 79 | | extend = NoBreak 80 | , spacingMark = NoBreak 81 | , zwj = NoBreak 82 | } 83 | , describeFollowing "regional indicator character" 84 | regionalIndicatorCharacter 85 | { breakForEverything 86 | | extend = NoBreak 87 | , regionalIndicator = NoBreak 88 | , spacingMark = NoBreak 89 | , zwj = NoBreak 90 | } 91 | , describeFollowing "prepend character" 92 | prependCharacter 93 | { breakForEverything 94 | | other = NoBreak 95 | , extend = NoBreak 96 | , regionalIndicator = NoBreak 97 | , prepend = NoBreak 98 | , spacingMark = NoBreak 99 | , l = NoBreak 100 | , v = NoBreak 101 | , t = NoBreak 102 | , lv = NoBreak 103 | , lvt = NoBreak 104 | , extendedPictographic = NoBreak 105 | , zwj = NoBreak 106 | } 107 | , describeFollowing "spacing mark" 108 | spacingMarkCharacter 109 | { breakForEverything 110 | | extend = NoBreak 111 | , spacingMark = NoBreak 112 | , zwj = NoBreak 113 | } 114 | , describeFollowing "Hangul L" 115 | lCharacter 116 | { breakForEverything 117 | | extend = NoBreak 118 | , spacingMark = NoBreak 119 | , l = NoBreak 120 | , v = NoBreak 121 | , lv = NoBreak 122 | , lvt = NoBreak 123 | , zwj = NoBreak 124 | } 125 | , describeFollowing "Hangul V" 126 | vCharacter 127 | { breakForEverything 128 | | extend = NoBreak 129 | , spacingMark = NoBreak 130 | , v = NoBreak 131 | , t = NoBreak 132 | , zwj = NoBreak 133 | } 134 | , describeFollowing "Hangul T" 135 | tCharacter 136 | { breakForEverything 137 | | extend = NoBreak 138 | , spacingMark = NoBreak 139 | , t = NoBreak 140 | , zwj = NoBreak 141 | } 142 | , describeFollowing "Hangul LV" 143 | lvCharacter 144 | { breakForEverything 145 | | extend = NoBreak 146 | , spacingMark = NoBreak 147 | , v = NoBreak 148 | , t = NoBreak 149 | , zwj = NoBreak 150 | } 151 | , describeFollowing "Hangul LVT" 152 | lvtCharacter 153 | { breakForEverything 154 | | extend = NoBreak 155 | , spacingMark = NoBreak 156 | , t = NoBreak 157 | , zwj = NoBreak 158 | } 159 | , describeFollowing "extended pictographic" 160 | extendedPictographicCharacter 161 | { breakForEverything 162 | | extend = NoBreak 163 | , spacingMark = NoBreak 164 | , zwj = NoBreak 165 | } 166 | , describeFollowing "ZWJ" 167 | zwjCharacter 168 | { breakForEverything 169 | | extend = NoBreak 170 | , spacingMark = NoBreak 171 | , zwj = NoBreak 172 | } 173 | , describeFollowing "other character" 174 | otherCharacter 175 | { breakForEverything 176 | | extend = NoBreak 177 | , spacingMark = NoBreak 178 | , zwj = NoBreak 179 | } 180 | ] 181 | , describe "rules" 182 | (List.map 183 | (\( name, fuzzer ) -> 184 | fuzz fuzzer name <| 185 | \sequence -> 186 | sequence 187 | |> String.join "" 188 | |> toList 189 | |> Expect.equal sequence 190 | ) 191 | [ -- rule numbers from -- https://www.unicode.org/Public/12.1.0/ucd/auxiliary/GraphemeBreakTest.html 192 | -- rules 0.2 and 0.3 deal with the bounds of the string; we don't 193 | -- explicitly need to model these. 194 | ( "rule 3.0" 195 | , Fuzz.map2 (\cr lf -> [ cr ++ lf ]) 196 | crCharacter 197 | lfCharacter 198 | ) 199 | , -- TODO: need a way to generate valid sequences recursively to properly test 200 | ( "rule 4.0" 201 | , Fuzz.map2 (\control anything -> [ control, anything ]) 202 | controlCharacter 203 | otherCharacter 204 | ) 205 | , -- TODO: need a way to generate valid sequences recursively to properly test 206 | ( "rule 5.0" 207 | , Fuzz.map2 (\anything control -> [ anything, control ]) 208 | otherCharacter 209 | controlCharacter 210 | ) 211 | , ( "rule 6.0" 212 | , Fuzz.map2 (\l otherHangul -> [ l ++ otherHangul ]) 213 | lCharacter 214 | (Fuzz.oneOf 215 | [ lCharacter 216 | , vCharacter 217 | , lvCharacter 218 | , lvtCharacter 219 | ] 220 | ) 221 | ) 222 | , ( "rule 7.0" 223 | , Fuzz.map2 (\a b -> [ a ++ b ]) 224 | (Fuzz.oneOf 225 | [ lvCharacter 226 | , vCharacter 227 | ] 228 | ) 229 | (Fuzz.oneOf 230 | [ vCharacter 231 | , tCharacter 232 | ] 233 | ) 234 | ) 235 | , ( "rule 8.0" 236 | , Fuzz.map2 (\a b -> [ a ++ b ]) 237 | (Fuzz.oneOf 238 | [ lvCharacter 239 | , lvtCharacter 240 | ] 241 | ) 242 | tCharacter 243 | ) 244 | , -- TODO: need a way to generate valid sequences recursively to properly test 245 | ( "rule 9.0" 246 | , Fuzz.map2 (\anything zwj -> [ anything ++ zwj ]) 247 | otherCharacter 248 | zwjCharacter 249 | ) 250 | , -- TODO: need a way to generate valid sequences recursively to properly test 251 | ( "rule 9.1" 252 | , Fuzz.map2 (\anything spacingMark -> [ anything ++ spacingMark ]) 253 | otherCharacter 254 | spacingMarkCharacter 255 | ) 256 | , -- TODO: need a way to generate valid sequences recursively to properly test 257 | ( "rule 9.2" 258 | , Fuzz.map2 (\prepend anything -> [ prepend ++ anything ]) 259 | prependCharacter 260 | otherCharacter 261 | ) 262 | 263 | -- Nope, no rule 10. Why? Has to do with the numbering in the 264 | -- spec the rules are numbered based on. 265 | , ( "rule 11.0" 266 | , Fuzz.map4 (\xp1 extends zwj xp2 -> [ xp1 ++ String.join "" extends ++ zwj ++ xp2 ]) 267 | extendedPictographicCharacter 268 | (Fuzz.list extendCharacter) 269 | zwjCharacter 270 | extendedPictographicCharacter 271 | ) 272 | , ( "rule 12.0" 273 | , Fuzz.map3 (\ris ri1 ri2 -> ris ++ [ ri1 ++ ri2 ]) 274 | (list (Fuzz.map2 (++) regionalIndicatorCharacter regionalIndicatorCharacter)) 275 | regionalIndicatorCharacter 276 | regionalIndicatorCharacter 277 | ) 278 | , -- TODO: need a way to generate valid sequences recursively to properly test 279 | ( "rule 13.0" 280 | , Fuzz.map4 (\notRi ris ri1 ri2 -> notRi :: ris ++ [ ri1 ++ ri2 ]) 281 | otherCharacter 282 | (list (Fuzz.map2 (++) regionalIndicatorCharacter regionalIndicatorCharacter)) 283 | regionalIndicatorCharacter 284 | regionalIndicatorCharacter 285 | ) 286 | , -- TODO: need a way to generate valid sequences recursively to properly test 287 | ( "rule 999.0" 288 | , Fuzz.map2 (\a b -> [ a, b ]) 289 | otherCharacter 290 | otherCharacter 291 | ) 292 | ] 293 | ) 294 | ] 295 | 296 | 297 | type Break 298 | = Break 299 | | NoBreak 300 | 301 | 302 | breakForEverything = 303 | { other = Break 304 | , cr = Break 305 | , lf = Break 306 | , control = Break 307 | , extend = Break 308 | , regionalIndicator = Break 309 | , prepend = Break 310 | , spacingMark = Break 311 | , l = Break 312 | , v = Break 313 | , t = Break 314 | , lv = Break 315 | , lvt = Break 316 | , extendedPictographic = Break 317 | , zwj = Break 318 | } 319 | 320 | 321 | describeFollowing : 322 | String 323 | -> Fuzzer String 324 | -> 325 | { other : Break 326 | , cr : Break 327 | , lf : Break 328 | , control : Break 329 | , extend : Break 330 | , regionalIndicator : Break 331 | , prepend : Break 332 | , spacingMark : Break 333 | , l : Break 334 | , v : Break 335 | , t : Break 336 | , lv : Break 337 | , lvt : Break 338 | , extendedPictographic : Break 339 | , zwj : Break 340 | } 341 | -> Test 342 | describeFollowing description fuzzer tests = 343 | describe description 344 | [ breakTest fuzzer otherCharacter tests.other "other character" 345 | , breakTest fuzzer crCharacter tests.cr "carriage return character" 346 | , breakTest fuzzer lfCharacter tests.lf "line feed character" 347 | , breakTest fuzzer controlCharacter tests.control "control character" 348 | , breakTest fuzzer extendCharacter tests.extend "extend character" 349 | , breakTest fuzzer regionalIndicatorCharacter tests.regionalIndicator "regional indicator character" 350 | , breakTest fuzzer prependCharacter tests.prepend "prepend character" 351 | , breakTest fuzzer spacingMarkCharacter tests.spacingMark "spacing mark character" 352 | , breakTest fuzzer lCharacter tests.l "hangul L character" 353 | , breakTest fuzzer vCharacter tests.v "hangul V character" 354 | , breakTest fuzzer tCharacter tests.t "hangul T character" 355 | , breakTest fuzzer lvCharacter tests.lv "hangul LV character" 356 | , breakTest fuzzer lvtCharacter tests.lvt "hangul LVT character" 357 | , breakTest fuzzer extendedPictographicCharacter tests.extendedPictographic "extended pictographic character" 358 | , breakTest fuzzer zwjCharacter tests.zwj "ZWJ character" 359 | ] 360 | 361 | 362 | breakTest : Fuzzer String -> Fuzzer String -> Break -> String -> Test 363 | breakTest first second break name = 364 | case break of 365 | Break -> 366 | fuzz2 367 | first 368 | second 369 | ("breaks on " ++ name) 370 | expectSplit 371 | 372 | NoBreak -> 373 | fuzz 374 | (Fuzz.map2 (++) first second) 375 | ("does not break on " ++ name) 376 | expectIdentity 377 | 378 | 379 | expectIdentity : String -> Expectation 380 | expectIdentity s = 381 | Expect.equal [ s ] (toList s) 382 | 383 | 384 | expectSplit : String -> String -> Expectation 385 | expectSplit c1 c2 = 386 | (c1 ++ c2) 387 | |> toList 388 | |> Expect.equal [ c1, c2 ] 389 | 390 | 391 | otherCharacter : Fuzzer String 392 | otherCharacter = 393 | Fuzz.intRange (Char.toCode 'A') (Char.toCode 'z') 394 | |> Fuzz.map Char.fromCode 395 | |> Fuzz.map List.singleton 396 | |> Fuzz.map String.fromList 397 | 398 | 399 | crCharacter : Fuzzer String 400 | crCharacter = 401 | RangeDictFuzzer.fromChars CR.chars 402 | 403 | 404 | lfCharacter : Fuzzer String 405 | lfCharacter = 406 | RangeDictFuzzer.fromChars LF.chars 407 | 408 | 409 | controlCharacter : Fuzzer String 410 | controlCharacter = 411 | RangeDictFuzzer.fromChars Control.chars 412 | 413 | 414 | prependCharacter : Fuzzer String 415 | prependCharacter = 416 | RangeDictFuzzer.fromChars Prepend.chars 417 | 418 | 419 | extendCharacter : Fuzzer String 420 | extendCharacter = 421 | RangeDictFuzzer.fromChars Extend.chars 422 | 423 | 424 | regionalIndicatorCharacter : Fuzzer String 425 | regionalIndicatorCharacter = 426 | RangeDictFuzzer.fromChars RegionalIndicator.chars 427 | 428 | 429 | spacingMarkCharacter : Fuzzer String 430 | spacingMarkCharacter = 431 | RangeDictFuzzer.fromChars SpacingMark.chars 432 | 433 | 434 | lCharacter : Fuzzer String 435 | lCharacter = 436 | RangeDictFuzzer.fromChars L.chars 437 | 438 | 439 | vCharacter : Fuzzer String 440 | vCharacter = 441 | RangeDictFuzzer.fromChars V.chars 442 | 443 | 444 | tCharacter : Fuzzer String 445 | tCharacter = 446 | RangeDictFuzzer.fromChars T.chars 447 | 448 | 449 | lvCharacter : Fuzzer String 450 | lvCharacter = 451 | RangeDictFuzzer.fromChars LV.chars 452 | 453 | 454 | lvtCharacter : Fuzzer String 455 | lvtCharacter = 456 | RangeDictFuzzer.fromChars LVT.chars 457 | 458 | 459 | extendedPictographicCharacter : Fuzzer String 460 | extendedPictographicCharacter = 461 | RangeDictFuzzer.fromChars ExtendedPictographic.chars 462 | 463 | 464 | zwjCharacter : Fuzzer String 465 | zwjCharacter = 466 | RangeDictFuzzer.fromChars ZWJ.chars 467 | -------------------------------------------------------------------------------- /tests/String/Graphemes/RangeDict/RangeSpec.elm: -------------------------------------------------------------------------------- 1 | module String.Graphemes.RangeDict.RangeSpec exposing (compareSpec) 2 | 3 | import Expect 4 | import Fuzz exposing (Fuzzer) 5 | import String.Graphemes.RangeDict.Range as Range exposing (..) 6 | import Test exposing (..) 7 | 8 | 9 | compareSpec : Test 10 | compareSpec = 11 | describe "compare" 12 | [ describe "LTs" 13 | [ fuzz Fuzz.int "point / range" <| 14 | \i -> 15 | Range.compare (point (i - 1)) (range i (i + 1)) 16 | |> Expect.equal Range.LT 17 | , fuzz Fuzz.int "range / point " <| 18 | \i -> 19 | Range.compare (range (i - 1) i) (point (i + 1)) 20 | |> Expect.equal Range.LT 21 | , fuzz Fuzz.int "range / range" <| 22 | \i -> 23 | Range.compare (range (i - 2) (i - 1)) (range i (i + 1)) 24 | |> Expect.equal Range.LT 25 | , fuzz Fuzz.int "point / point" <| 26 | \i -> 27 | Range.compare (point (i - 1)) (point i) 28 | |> Expect.equal Range.LT 29 | ] 30 | , describe "GTs" 31 | [ fuzz Fuzz.int "point / range" <| 32 | \i -> 33 | Range.compare (point (i + 1)) (range (i - 1) i) 34 | |> Expect.equal Range.GT 35 | , fuzz Fuzz.int "range / point" <| 36 | \i -> 37 | Range.compare (range i (i + 1)) (point (i - 1)) 38 | |> Expect.equal Range.GT 39 | , fuzz Fuzz.int "range / range" <| 40 | \i -> 41 | Range.compare (range i (i + 1)) (range (i - 2) (i - 1)) 42 | |> Expect.equal Range.GT 43 | , fuzz Fuzz.int "point / point" <| 44 | \i -> 45 | Range.compare (point i) (point (i - 1)) 46 | |> Expect.equal Range.GT 47 | ] 48 | , describe "EQs" 49 | [ fuzz Fuzz.int "point / range" <| 50 | \i -> 51 | Range.compare (point i) (range i (i + 1)) 52 | |> Expect.notEqual Range.EQ 53 | , fuzz Fuzz.int "range / point" <| 54 | \i -> 55 | Range.compare (range i (i + 1)) (point i) 56 | |> Expect.notEqual Range.EQ 57 | , fuzz Fuzz.int "point / point" <| 58 | \i -> 59 | Range.compare (point i) (point i) 60 | |> Expect.equal Range.EQ 61 | , fuzz2 Fuzz.int Fuzz.int "range / range" <| 62 | \i j -> 63 | Range.compare (range i j) (range i j) 64 | |> Expect.equal Range.EQ 65 | ] 66 | , describe "overlapping" 67 | [ fuzz2 Fuzz.int Fuzz.int "point / point" <| 68 | \i j -> 69 | Range.compare (point i) (point j) 70 | |> Expect.notEqual Range.Overlapping 71 | , fuzz Fuzz.int "point / range" <| 72 | \i -> 73 | Range.compare (point i) (range (i - 1) (i + 1)) 74 | |> Expect.equal Range.Overlapping 75 | , fuzz Fuzz.int "range / point" <| 76 | \i -> 77 | Range.compare (range (i - 1) (i + 1)) (point i) 78 | |> Expect.equal Range.Overlapping 79 | , fuzz Fuzz.int "range / range" <| 80 | \i -> 81 | Range.compare (range (i - 1) i) (range i (i + 1)) 82 | |> Expect.equal Range.Overlapping 83 | ] 84 | ] 85 | -------------------------------------------------------------------------------- /tests/String/GraphemesSpec.elm: -------------------------------------------------------------------------------- 1 | module String.GraphemesSpec exposing (spec) 2 | 3 | import Array 4 | import Expect 5 | import Fuzz exposing (Fuzzer, float, int, list, string) 6 | import String.Graphemes as Graphemes 7 | import Test exposing (..) 8 | 9 | 10 | spec : Test 11 | spec = 12 | describe "String.Graphemes" 13 | [ describe "compatibility with elm/core String" 14 | [ fuzz simpleString "isEmpty" <| 15 | \s -> 16 | Expect.equal 17 | (String.isEmpty s) 18 | (Graphemes.isEmpty s) 19 | , fuzz simpleString "length" <| 20 | \s -> 21 | Expect.equal 22 | (String.length s) 23 | (Graphemes.length s) 24 | , fuzz simpleString "reverse" <| 25 | \s -> 26 | Expect.equal 27 | (String.reverse s) 28 | (Graphemes.reverse s) 29 | , fuzz2 (Fuzz.intRange -100 100) simpleString "repeat" <| 30 | \i s -> 31 | Expect.equal 32 | (String.repeat i s) 33 | (Graphemes.repeat i s) 34 | , fuzz3 simpleString simpleString simpleString "replace" <| 35 | \from to source -> 36 | Expect.equal 37 | (String.replace from to source) 38 | (Graphemes.replace from to source) 39 | , fuzz2 simpleString simpleString "append" <| 40 | \a b -> 41 | Expect.equal 42 | (String.append a b) 43 | (Graphemes.append a b) 44 | , fuzz (list simpleString) "concat" <| 45 | \strings -> 46 | Expect.equal 47 | (String.concat strings) 48 | (Graphemes.concat strings) 49 | , fuzz2 simpleString simpleString "split" <| 50 | \a b -> 51 | Expect.equal 52 | (String.split a b) 53 | (Graphemes.split a b) 54 | , fuzz2 simpleString (list simpleString) "join" <| 55 | \joiner strings -> 56 | Expect.equal 57 | (String.join joiner strings) 58 | (Graphemes.join joiner strings) 59 | , fuzz (Fuzz.map String.concat (list simpleString)) "words" <| 60 | \strings -> 61 | Expect.equal 62 | (String.words strings) 63 | (Graphemes.words strings) 64 | , fuzz (Fuzz.map (String.join "\n") (list simpleString)) "lines" <| 65 | \strings -> 66 | Expect.equal 67 | (String.lines strings) 68 | (Graphemes.lines strings) 69 | , fuzz3 int int simpleString "slice" <| 70 | \a b string -> 71 | Expect.equal 72 | (String.slice a b string) 73 | (Graphemes.slice a b string) 74 | , fuzz2 int simpleString "left" <| 75 | \offset string -> 76 | Expect.equal 77 | (String.left offset string) 78 | (Graphemes.left offset string) 79 | , fuzz2 int simpleString "right" <| 80 | \offset string -> 81 | Expect.equal 82 | (String.right offset string) 83 | (Graphemes.right offset string) 84 | , fuzz2 int simpleString "dropLeft" <| 85 | \offset string -> 86 | Expect.equal 87 | (String.dropLeft offset string) 88 | (Graphemes.dropLeft offset string) 89 | , fuzz2 int simpleString "dropRight" <| 90 | \offset string -> 91 | Expect.equal 92 | (String.dropRight offset string) 93 | (Graphemes.dropRight offset string) 94 | , fuzz2 simpleString simpleString "contains" <| 95 | \a b -> 96 | Expect.equal 97 | (String.contains a b) 98 | (Graphemes.contains a b) 99 | , fuzz2 simpleString simpleString "startsWith" <| 100 | \a b -> 101 | Expect.equal 102 | (String.startsWith a b) 103 | (Graphemes.startsWith a b) 104 | , fuzz2 simpleString simpleString "endsWith" <| 105 | \a b -> 106 | Expect.equal 107 | (String.endsWith a b) 108 | (Graphemes.endsWith a b) 109 | , fuzz2 simpleString simpleString "indexes" <| 110 | \a b -> 111 | Expect.equal 112 | (String.indexes a b) 113 | (Graphemes.indexes a b) 114 | , fuzz2 simpleString simpleString "indices" <| 115 | \a b -> 116 | Expect.equal 117 | (String.indices a b) 118 | (Graphemes.indices a b) 119 | , fuzz simpleString "toUpper" <| 120 | \string -> 121 | Expect.equal 122 | (String.toUpper string) 123 | (Graphemes.toUpper string) 124 | , fuzz simpleString "toLower" <| 125 | \string -> 126 | Expect.equal 127 | (String.toLower string) 128 | (Graphemes.toLower string) 129 | , fuzz3 (Fuzz.intRange 0 1000) simpleChar simpleString "pad" <| 130 | \howMuch what string -> 131 | Expect.equal 132 | (String.pad howMuch what string) 133 | (Graphemes.pad howMuch what string) 134 | , fuzz3 (Fuzz.intRange 0 1000) simpleChar simpleString "padLeft" <| 135 | \howMuch what string -> 136 | Expect.equal 137 | (String.padLeft howMuch what string) 138 | (Graphemes.padLeft howMuch what string) 139 | , fuzz3 (Fuzz.intRange 0 1000) simpleChar simpleString "padRight" <| 140 | \howMuch what string -> 141 | Expect.equal 142 | (String.padRight howMuch what string) 143 | (Graphemes.padRight howMuch what string) 144 | , fuzz simpleString "trim" <| 145 | \string -> 146 | Expect.equal 147 | (String.trim string) 148 | (Graphemes.trim string) 149 | , fuzz simpleString "trimLeft" <| 150 | \string -> 151 | Expect.equal 152 | (String.trimLeft string) 153 | (Graphemes.trimLeft string) 154 | , fuzz simpleString "trimRight" <| 155 | \string -> 156 | Expect.equal 157 | (String.trimRight string) 158 | (Graphemes.trimRight string) 159 | , fuzz simpleString "toInt" <| 160 | \string -> 161 | Expect.equal 162 | (String.toInt string) 163 | (Graphemes.toInt string) 164 | , fuzz int "fromInt" <| 165 | \i -> 166 | Expect.equal 167 | (String.fromInt i) 168 | (Graphemes.fromInt i) 169 | , fuzz simpleString "toFloat" <| 170 | \string -> 171 | Expect.equal 172 | (String.toFloat string) 173 | (Graphemes.toFloat string) 174 | , fuzz float "fromFloat" <| 175 | \i -> 176 | Expect.equal 177 | (String.fromFloat i) 178 | (Graphemes.fromFloat i) 179 | , fuzz simpleString "toList" <| 180 | \string -> 181 | Expect.equal 182 | (String.toList string |> List.map String.fromChar) 183 | (Graphemes.toList string) 184 | , fuzz (list simpleChar) "fromList" <| 185 | \chars -> 186 | Expect.equal 187 | (String.fromList chars) 188 | (chars |> List.map String.fromChar |> Graphemes.fromList) 189 | , fuzz simpleChar "fromChar" <| 190 | \char -> 191 | Expect.equal 192 | (String.fromChar char) 193 | (Graphemes.fromChar char) 194 | , fuzz2 simpleChar simpleString "cons" <| 195 | \char string -> 196 | Expect.equal 197 | (String.cons char string) 198 | (Graphemes.cons char string) 199 | , fuzz simpleString "uncons" <| 200 | \string -> 201 | Expect.equal 202 | (string 203 | |> String.uncons 204 | |> Maybe.map (Tuple.mapFirst String.fromChar) 205 | ) 206 | (Graphemes.uncons string) 207 | , fuzz simpleString "map" <| 208 | \string -> 209 | Expect.equal 210 | (String.map (always 'a') string) 211 | (Graphemes.map (always "a") string) 212 | , fuzz simpleString "filter" <| 213 | \string -> 214 | Expect.equal 215 | (String.filter ((/=) '!') string) 216 | (Graphemes.filter ((/=) "!") string) 217 | , fuzz simpleString "foldl" <| 218 | \string -> 219 | Expect.equal 220 | (String.foldl String.cons "" string) 221 | (Graphemes.foldl (++) "" string) 222 | , fuzz simpleString "foldr" <| 223 | \string -> 224 | Expect.equal 225 | (String.foldr String.cons "" string) 226 | (Graphemes.foldr (++) "" string) 227 | , fuzz simpleString "any" <| 228 | \string -> 229 | Expect.equal 230 | (String.any Char.isDigit string) 231 | (Graphemes.any (String.any Char.isDigit) string) 232 | , fuzz simpleString "all" <| 233 | \string -> 234 | Expect.equal 235 | (String.all Char.isDigit string) 236 | (Graphemes.all (String.all Char.isDigit) string) 237 | ] 238 | , describe "make sure relevant functions work with graphemes" 239 | [ fuzz graphemesFuzzer "length produces the graphemes length" <| 240 | \graphemes -> 241 | graphemes 242 | |> String.concat 243 | |> Graphemes.length 244 | |> Expect.equal (List.length graphemes) 245 | , fuzz graphemesFuzzer "reverse respects graphemes" <| 246 | \graphemes -> 247 | graphemes 248 | |> String.concat 249 | |> Graphemes.reverse 250 | |> Expect.equal (String.concat (List.reverse graphemes)) 251 | , describe "slice" <| 252 | let 253 | flags = 254 | "🇨🇦🇺🇸🇲🇽" 255 | in 256 | [ test "selecting a part from the front" <| 257 | \_ -> 258 | flags 259 | |> Graphemes.slice 0 2 260 | |> Expect.equal "🇨🇦🇺🇸" 261 | , test "selecting a part from the back" <| 262 | \_ -> 263 | flags 264 | |> Graphemes.slice -2 3 265 | |> Expect.equal "🇺🇸🇲🇽" 266 | , test "selecting a part in the middle" <| 267 | \_ -> 268 | flags 269 | |> Graphemes.slice 1 2 270 | |> Expect.equal "🇺🇸" 271 | ] 272 | , fuzz2 int graphemesFuzzer "left" <| 273 | \n graphemes -> 274 | graphemes 275 | |> String.concat 276 | |> Graphemes.left n 277 | |> Expect.equal (String.concat (List.take n graphemes)) 278 | , fuzz2 int graphemesFuzzer "right" <| 279 | \n graphemes -> 280 | graphemes 281 | |> String.concat 282 | |> Graphemes.right n 283 | |> Expect.equal (String.concat (List.drop (List.length graphemes - n) graphemes)) 284 | , fuzz2 int graphemesFuzzer "dropLeft" <| 285 | \n graphemes -> 286 | graphemes 287 | |> String.concat 288 | |> Graphemes.dropLeft n 289 | |> Expect.equal (String.concat (List.drop n graphemes)) 290 | , fuzz2 int graphemesFuzzer "dropRight" <| 291 | \n graphemes -> 292 | graphemes 293 | |> String.concat 294 | |> Graphemes.dropRight n 295 | |> Expect.equal (String.concat (List.take (List.length graphemes - n) graphemes)) 296 | , fuzz3 (Fuzz.intRange 0 100) simpleChar graphemesFuzzer "pad" <| 297 | \n padder graphemes -> 298 | graphemes 299 | |> String.concat 300 | |> Graphemes.pad n padder 301 | |> Graphemes.length 302 | |> Expect.equal (max n (List.length graphemes)) 303 | , fuzz3 (Fuzz.intRange 0 100) simpleChar graphemesFuzzer "padLeft" <| 304 | \n padder graphemes -> 305 | graphemes 306 | |> String.concat 307 | |> Graphemes.padLeft n padder 308 | |> Graphemes.length 309 | |> Expect.equal (max n (List.length graphemes)) 310 | , fuzz3 (Fuzz.intRange 0 100) simpleChar graphemesFuzzer "padRight" <| 311 | \n padder graphemes -> 312 | graphemes 313 | |> String.concat 314 | |> Graphemes.padRight n padder 315 | |> Graphemes.length 316 | |> Expect.equal (max n (List.length graphemes)) 317 | , fuzz graphemesFuzzer "toList" <| 318 | \graphemes -> 319 | graphemes 320 | |> String.concat 321 | |> Graphemes.toList 322 | |> Expect.equal graphemes 323 | , fuzz graphemesFuzzer "uncons" <| 324 | \graphemes -> 325 | graphemes 326 | |> String.concat 327 | |> Graphemes.uncons 328 | |> Expect.equal 329 | (Maybe.map2 Tuple.pair 330 | (List.head graphemes) 331 | (List.tail graphemes |> Maybe.map Graphemes.concat) 332 | ) 333 | , fuzz graphemesFuzzer "map" <| 334 | \graphemes -> 335 | graphemes 336 | |> String.concat 337 | |> Graphemes.map (always "a") 338 | |> Expect.equal (String.repeat (List.length graphemes) "a") 339 | , fuzz graphemesFuzzer "filter" <| 340 | \graphemes -> 341 | graphemes 342 | |> String.concat 343 | |> Graphemes.filter (\g -> String.length g <= 1) 344 | |> Expect.equal (String.concat (List.filter (\g -> String.length g <= 1) graphemes)) 345 | , fuzz graphemesFuzzer "any" <| 346 | \graphemes -> 347 | graphemes 348 | |> String.concat 349 | |> Graphemes.any (String.all Char.isDigit) 350 | |> Expect.equal (List.any (String.all Char.isDigit) graphemes) 351 | , fuzz graphemesFuzzer "all" <| 352 | \graphemes -> 353 | graphemes 354 | |> String.concat 355 | |> Graphemes.all (String.all Char.isDigit) 356 | |> Expect.equal (List.all (String.all Char.isDigit) graphemes) 357 | ] 358 | ] 359 | 360 | 361 | simpleChar : Fuzzer Char 362 | simpleChar = 363 | Fuzz.intRange (Char.toCode '!') (Char.toCode 'Z') 364 | |> Fuzz.map Char.fromCode 365 | 366 | 367 | simpleString : Fuzzer String 368 | simpleString = 369 | Fuzz.map String.fromList (list simpleChar) 370 | 371 | 372 | flag : Fuzzer String 373 | flag = 374 | let 375 | regionalIndicator = 376 | Fuzz.intRange (Char.toCode '🇦') (Char.toCode '🇿') 377 | |> Fuzz.map Char.fromCode 378 | |> Fuzz.map String.fromChar 379 | in 380 | Fuzz.map2 (++) regionalIndicator regionalIndicator 381 | 382 | 383 | graphemeFuzzer : Fuzzer String 384 | graphemeFuzzer = 385 | Fuzz.oneOf 386 | [ flag 387 | , Fuzz.map String.fromChar simpleChar 388 | ] 389 | 390 | 391 | graphemesFuzzer : Fuzzer (List String) 392 | graphemesFuzzer = 393 | list graphemeFuzzer 394 | -------------------------------------------------------------------------------- /tests/elm-verify-examples.json: -------------------------------------------------------------------------------- 1 | { 2 | "root": "../src", 3 | "tests": ["String.Graphemes", "./README.md"] 4 | } 5 | --------------------------------------------------------------------------------