std/unicode
import std/unicode to use it. Source: src/std/unicode.iyi at v0.18.0.
The tables between # tables-begin and # tables-end are written by scripts/generate_unicode_std.py from the UCD data the repository already carries (VERSION says which release) and, for Cased and Case_Ignorable, from DerivedCoreProperties.txt of the same release; they are not to be edited by hand. Each is a string of decimal integers decoded into an Array(Int32) the first time it is asked for, and every lookup is a binary search over rows of two, three or four integers.
What it answers, all under Unicode.:
* `letter?`, `number?`, `mark?`, `whitespace?`, `control?`, `lowercase?`,
`uppercase?`, `titlecase?`, `ascii?` — the general categories, exact:
`control?` is Cc, Cf, Cs and Co; `whitespace?` is Zs, Zl and Zp.
* `general_category` and `script` of a `Char` — `"Lu"`, `"Po"`, `"Cn"`
for unassigned; `"Greek"`, `"Common"`, `"Unknown"` — and
`property_ranges`, the code points of a category, a major class (`"P"`)
or a script as sorted `{from, to}` pairs, which `std/regex` builds
`\p{..}` from.
* `upcase`, `downcase`, `titlecase`, `foldcase` of a `Char` — the simple
one-to-one mappings; with a block, the full mappings (`ß` upcases to
`S`, `S`). `CaseOptions::ASCII` touches only ASCII, `Turkic` maps the
dotted and dotless i, `Fold` makes `downcase` fold.
`case_orbit` is every character with the same simple folding (`k`,
`K` and the Kelvin sign), what a case-insensitive match accepts, and
`each_case_orbit` yields every orbit of more than one.
* `upcase`, `downcase`, `capitalize`, `foldcase` of a `String` — the full
mappings, and `downcase` writes the final sigma: a `Σ` that ends a word
becomes `ς`.
* `valid?` and `clean` — whether bytes are well-formed UTF-8 (overlong
forms, surrogates, code points past U+10FFFF and truncated sequences are
not), and the same bytes with every maximal ill-formed subpart replaced
by U+FFFD.
* `encode_utf16` and `decode_utf16` — UTF-16 code units as `Array(UInt16)`.
* `normalize` and `normalized?` — NFD, NFC, NFKD and NFKC, with canonical
ordering by combining class and algorithmic Hangul.
* `graphemes`, `each_grapheme` and `grapheme_size` — the extended
grapheme clusters of UAX #29, every rule through GB9c's Indic
conjuncts, on `Unicode.` and on `String` itself: `"🇹🇷🇩🇪".graphemes` is
two flags. A piece of ill-formed UTF-8 is a cluster of its own.What it refuses: a string that is not well-formed UTF-8 is not case-mapped, encoded or normalized, it panics with the byte offset ("invalid UTF-8 at byte 3"); an unpaired surrogate in UTF-16 is nil from decode_utf16? and a panic from decode_utf16.
Unicodestruct
pub struct Unicode
# Options the case mappings take; combine them with `|`.
enum CaseOptions : Int32
ASCII = 1
Turkic = 2
Fold = 4
end
# The normalization forms `normalize` writes.
enum NormalizationForm : Int32
NFD = 0
NFC = 1
NFKD = 2
NFKC = 3
end
def self.ascii?(char : Char) : Bool
# The first character in titlecase and the rest in lowercase: `"džemal"` is
# `"Džemal"`, `"STRASSE"` is `"Strasse"`. The first character is still a
# letter before the rest, so `"ΑΣ"` is `"Ας"`.
def self.capitalize(text : String, options : CaseOptions = CaseOptions::None) : String
# Every character whose simple case folding is this one's, itself among
# them, in code point order: `k` answers `K`, `k` and the Kelvin sign
# U+212A, `σ` answers `Σ`, `ς` and `σ`, and `ß` answers `ß` and `ẞ`. A
# character without case answers itself alone. It is what a
# case-insensitive comparison of one character has to accept, and folding
# both sides is not enough to build it: a class holding the Kelvin sign
# has to take `K` as well, and only the folding read backwards says so.
#
# The simple folding here is CaseFolding.txt's C and S rows, which is
# RE2's. `foldcase` answers the other library's, which has no S rows:
# there `ẞ` folds to itself.
def self.case_orbit(char : Char) : Array(Char)
# The string with every maximal ill-formed subpart replaced by U+FFFD; a
# well-formed string is answered as it is.
def self.clean(text : String) : String
# The bytes as a string, every maximal ill-formed subpart replaced by U+FFFD.
def self.clean(bytes : Array(UInt8)) : String
# Category C: Cc, Cf, Cs and Co — controls, format characters,
# surrogates and private use.
def self.control?(char : Char) : Bool
# The string the UTF-16 code units spell. An unpaired surrogate is refused
# with its index: `unpaired surrogate 0xD800 at index 3`.
def self.decode_utf16(units : Array(UInt16)) : String
# The string the UTF-16 code units spell, or nil at an unpaired surrogate.
def self.decode_utf16?(units : Array(UInt16)) : String | ::Nil
# The lowercase of one character, the simple mapping: `İ` becomes `i`
# under Turkic rules and stays `İ` otherwise, because its full mapping is
# `i` plus a combining dot.
def self.downcase(char : Char, options : CaseOptions = CaseOptions::None) : Char
# The full lowercase mapping, one character at a time.
def self.downcase(char : Char, options : CaseOptions = CaseOptions::None, & : (Char -> Nil)) : Nil
# The string in lowercase, full mappings, with the final sigma: a capital
# sigma that ends a word — a cased letter before it, none after, the
# case-ignorable characters (combining marks, format characters, modifier
# letters and the apostrophes, periods and colons that can sit inside a
# word) looked through — becomes `ς`, so `"ΟΔΥΣΣΕΥΣ"` is `"οδυσσευς"`.
# With `CaseOptions::Fold` this is `foldcase`.
def self.downcase(text : String, options : CaseOptions = CaseOptions::None) : String
# Every orbit `case_orbit` answers that holds more than one character,
# each once, as code points in order and in no particular order between
# them. A case-insensitive class folds itself against these, about 1,400
# of them, rather than asking `case_orbit` of each of the hundred
# thousand code points a class like `\p{L}` holds.
def self.each_case_orbit(& : (Array(Int32) -> Nil)) : Nil
# Each grapheme cluster, in order.
def self.each_grapheme(text : String, &block : (String -> _)) : Nil
# The string's UTF-16 code units: one per character up to U+FFFF, a
# surrogate pair above.
def self.encode_utf16(text : String) : Array(UInt16)
# The case folding of one character where it is one code point (`Σ`, `σ`
# and `ς` all fold to `σ`); a character whose folding is longer, like `ß`,
# is answered unchanged — the block form and the string form fold it.
def self.foldcase(char : Char) : Char
# The full case folding, one character at a time: `ß` yields `s` twice.
def self.foldcase(char : Char, & : (Char -> Nil)) : Nil
# The string folded for comparison: `"Straße"` and `"STRASSE"` both fold
# to `"strasse"`.
def self.foldcase(text : String) : String
# The two-letter general category of a character: `"Lu"` for `A`, `"Po"`
# for `!`, `"Sm"` for `+`; `"Cn"` for a code point no character is
# assigned to.
def self.general_category(char : Char) : String
# How many grapheme clusters the string has: what a reader counts.
def self.grapheme_size(text : String) : Int32
# The string's extended grapheme clusters, as UAX #29 divides them: what
# a reader sees as one character - `e` and a combining acute, a flag's
# two regional indicators, a family emoji joined by ZWJs, a Devanagari
# conjunct - is one string. A piece of ill-formed UTF-8 is a cluster of
# its own, as the U+FFFD that stands for it would be.
def self.graphemes(text : String) : Array(String)
def initialize
# Category L: Lu, Ll, Lt, Lm and Lo.
def self.letter?(char : Char) : Bool
# Category Ll.
def self.lowercase?(char : Char) : Bool
# Category M: Mn, Mc and Me — the combining marks.
def self.mark?(char : Char) : Bool
# The string in the given normalization form, NFC when none is named.
def self.normalize(text : String, form : NormalizationForm = NormalizationForm::NFC) : String
# Whether the string is already in the given form.
def self.normalized?(text : String, form : NormalizationForm = NormalizationForm::NFC) : Bool
# Category N: Nd, Nl and No — digits in every script, letter numbers, and
# the fractions and superscripts.
def self.number?(char : Char) : Bool
# The code points a property names, as sorted `{from, to}` pairs that
# neither overlap nor touch: a general category (`"Lu"`), a major class
# by its letter (`"L"` is Lu, Ll, Lt, Lm and Lo; `"C"` is Cc, Cf, Cs and
# Co, unassigned code points being in no category), or a script
# (`"Greek"`). Nil for a name that is none of those. A class is built
# from the ranges once rather than asking per character, which is what a
# regex's `\p{..}` needs: ranges it can negate and case-fold.
def self.property_ranges(name : String) : Array(Int32) | ::Nil
# The script a character is written in, as `Scripts.txt` names it:
# `"Latin"`, `"Greek"`, `"Han"`, and `"Common"` for the digits and
# punctuation every script shares; `"Unknown"` for a code point the file
# does not list.
def self.script(char : Char) : String
# The titlecase of one character, the simple mapping: the uppercase, except
# for the digraphs, where `dž` and `DŽ` both become `Dž`.
def self.titlecase(char : Char, options : CaseOptions = CaseOptions::None) : Char
# The full titlecase mapping, one character at a time: `ß` yields `S`, `s`.
def self.titlecase(char : Char, options : CaseOptions = CaseOptions::None, & : (Char -> Nil)) : Nil
# Category Lt: the digraphs whose first half is capital, `Dž` and `ᾈ`.
def self.titlecase?(char : Char) : Bool
# The uppercase of one character: the simple mapping, so `ß` stays `ß`
# (its full mapping is two letters; the block form gives it).
def self.upcase(char : Char, options : CaseOptions = CaseOptions::None) : Char
# The full uppercase mapping, one character at a time: `ß` yields `S` twice,
# `ʼn` yields `ʼ` and `N`.
def self.upcase(char : Char, options : CaseOptions = CaseOptions::None, & : (Char -> Nil)) : Nil
# The string in uppercase, full mappings: `"straße"` is `"STRASSE"`.
# An ASCII-only string is the prelude's `upcase`, unless the Turkic rule
# is on, which is a question about `i` itself.
def self.upcase(text : String, options : CaseOptions = CaseOptions::None) : String
# Category Lu.
def self.uppercase?(char : Char) : Bool
# Whether the string's bytes are well-formed UTF-8.
def self.valid?(text : String) : Bool
# Whether the bytes are well-formed UTF-8.
def self.valid?(bytes : Array(UInt8)) : Bool
# Category Z: Zs, Zl and Zp — the spaces and the line and paragraph
# separators. Tab and newline are controls, not whitespace, here.
def self.whitespace?(char : Char) : Bool
endStringclass, reopened
class ::String
def each_grapheme(&block : (String -> _)) : Nil
def grapheme_size : Int32
def graphemes : Array(String)
end
The Unicode Character Database, as questions a program asks of a character and of a string: which general category a code point is in, what its upper, lower, title and folded case are, whether a byte sequence is well-formed UTF-8, how a string reads in UTF-16, and the four normalization forms.