Wikikamus
mswiktionary
https://ms.wiktionary.org/wiki/Laman_Utama
MediaWiki 1.45.0-wmf.6
case-sensitive
Media
Khas
Perbincangan
Pengguna
Perbincangan pengguna
Wikikamus
Perbincangan Wikikamus
Fail
Perbincangan fail
MediaWiki
Perbincangan MediaWiki
Templat
Perbincangan templat
Bantuan
Perbincangan bantuan
Kategori
Perbincangan kategori
Lampiran
Perbincangan lampiran
Rima
Perbincangan rima
Tesaurus
Perbincangan tesaurus
Indeks
Perbincangan indeks
Petikan
Perbincangan petikan
Rekonstruksi
Perbincangan rekonstruksi
Padanan isyarat
Perbincangan padanan isyarat
Konkordans
Perbincangan konkordans
TimedText
TimedText talk
Modul
Perbincangan modul
Acara
Perbincangan acara
burung
0
5628
218850
217299
2025-06-20T10:01:06Z
Song GK
5715
218850
wikitext
text/x-wiki
{{wikipedia}}
{{ms}}
[[Fail:Blue Tit aka.jpg|thumb|Seekor burung.]]
===Sebutan===
* {{dewan|bu|rung}}
* {{a|Johor-Selangor}} {{IPA|ms|/buroŋ/}}
* {{a|Riau-Lingga}} {{IPA|ms|/burʊŋ/}}
* {{rima|ms|uroŋ|roŋ|oŋ}}
* {{audio|ms|ms-MY-burung.ogg|Audio (MY)}}
* {{a|Sebutan baku; Kamus Dewan Perdana}} {{IPA|ms|/bu.rung/}}
* {{audio|ms|LL-Q9237 (msa)-Hakimi97-burung.wav|Audio (MY-zsm)}}
===Terjemahan===
{{ter-atas|haiwan}}
* Afrikaan: voël
* Albania: {{t-|sq|zog|xs=Albania}}
* Arab: {{Arab|طير}} (tˁīr)
* Aragon: paxaro {{m}}
* Armenia: լժռչուն
* Azeri: quş
* Banjar: burung
* Basque: txori
* Belanda: {{t+|nl|vogel|m}}
* Bengali: পাখী
* Breton: labous {{m}}, laboused {{p}}, evn {{m}}, evned {{p}}
* Bosnia: {{t-|bs|ptica|f}}
* Bulgaria: {{t+|bg|птица|f|tr=ptitsa|sc=Cyrl}}
* Burma: ငဟက္ (hŋeʔ)
* Catalonia: au {{m}} {{penerang|kumpulan taksonomi}}, ocell {{m}} {{penerang|burung terbang}}
* Cebuano: langgam
* Cherokee: ᏥᏍᏆ (tsisqua)
* Cina: {{zh-ts|[[鳥]]|[[鸟]]}} (niăo); {{zh-ts|[[鳥類]]|[[鸟类]]}} (niăolèi); {{Hani|[[雀]]}} (què); {{zh-ts|[[雀鳥]]|[[雀鸟]]}} (quèniăo)
* Cree: pileshish, peepee
* Croatia: {{t+|hr|ptica|f}}
* Czech: {{t+|cs|pták|m}}
* Denmark: {{t+|da|fugl}}
* Erzya: нармунь (narmunj)
* Esperanto: {{t-|eo|birdo|xs=Bahasa Esperanto}}
* Estonia: {{t-|et|lind}}
* Faroe: {{t+|fo|fuglur|m|xs=Bahasa Faroe}}
* Farsi: {{FAchar|پَرَندِه}} (pærænde)
* Finland: {{t+|fi|lintu}}
* Frisia: fûgel
* Gaelik Scot: eun {{m}}
* Galicia: paxaro
* Georgia: ფრინველი (p‘rinveli)
* Jerman: {{t+|de|Vogel|m}}
* Greek,
*: Kuno: ὄρνις (ornis) {{f}}, πτηνό (ptēnó) {{n}}
*: Moden: πουλί (poulí) {{n}}, πτηνό (ptēnó) {{n}}
* Guaraní: guyra
* Gujarati: પનખિદ (pankhida)
* Guugu Yimidhirr: dyidyirr
* Hawaii: manu
* Hindi: चिड़िया (ći.riyā) {{f}}, पंछी (pančī) {{f}}, पक्षी (pakšī) {{m}}, परन्दा (parandā) {{m}}, पखेरू (pakherū) {{m}}
* Hungary: {{t+|hu|madár}}
* Ibrani: צפור (tzipor)
* Iceland: {{t+|is|fugl|m}}
* Ido: ucelo
* Indonesia: {{t+|id|burung|xs=Bahasa Indonesia}}
* Inggeris: {{t+|en|bird}}
* Inggeris Lama: {{t-|ang|fugol|xs=Bahasa Inggeris Lama}}
* Interlingua: ave
* Inuktitut: ᑎᖕᒥᐊᖅ (tingmiaq)
* Ireland: éan ''m1''
* Itali: {{t+|it|uccello|m}}
* Jepun: [[鳥]] (とり, tori)
* Kazakh: құс
* Khmer: {{KMchar|បក្សី}} (bʌksēi)
* Korea: 새 (sæ)
* Kurdi: firrinde, balinde, çivîk, çûçik, teyr, tilûr, terewîl, {{KUchar|باڵنده}}, {{KUchar|تهیر}}
* Ladino: ave, have {{f}}, pášaro, pážaro, pájaro, pásaro {{m}}
{{ter-tengah}}
* Lao: {{Laoo|ນົກ}} (nok)
* Latin: avis, -is
* Latvia: putns {{m}}
* Lithuania: paũkštis
* Macedonia: птица (ptica)
* Malagasy: vorona
* Malayalam: പക്ഷി, തടവറ, പറവ, വിഹഗം, കിളി, കുരുവി, പെണ്കുട്ടി, സ്ത്രീ, ജയില്ശിക്ഷ, പ്രത്യേകതയുള്ള വ്യക്തി
* Malta: tajra, għasfur
* Maori: {{t+|mi|manu|xs=Bahasa_Maori}}
* Mi'kmaq: jipji'j
* Mohikan: tschèchtschis
* Mongolia: {{t+|mn|шувуу|tr=šuvuu|sc=Cyrl|xs=Bahasa_Mongolia}}
* Nanticoke: piss-seeques
* Nenets: тиртя
* Nganasan: тәибәә
* Norway: {{t-|no|fugl|m}}
* Novial: fogle
* Occitan: {{italbrac|Lengadocian}} aucèl {{m}}, {{italbrac|Auvernhàs, Lemosin, Provençau}} aucèu {{m}} {{italbrac|Gascon}} ausèth {{m}}
* Ojibwe: bineshiinh
* Perancis: {{t+|fr|oiseau|m}}
* Poland: {{t+|pl|ptak|m}}
* Portugis: {{t+|pt|pássaro|m}}, {{t+|pt|ave|f}}
* Potawatomi: pnéshi
* Powhatan: tshehip
* Punjabi: ਪੰਖੀ
* Rohingya: faik
* Romania: {{t+|ro|pasăre|f}}
* Rusia: {{t+|ru|птица|f|tr=ptítsa|sc=Cyrl}}
* Samoa: manu
* Sanskrit: {{term|sc=Deva|वि|tr=ví|m}}
* Saxon Rendah: Vagel {{m}}
* Sepanyol: {{t+|es|pájaro|m}}, {{t+|es|ave|f}}
* Serbia:
*: Cyril: птица {{f}}
*: Rumi: ptica {{f}}
* Sicily: aceddu {{m}}
* Slovakia: vták {{m}}
* Slovenia: {{t+|sl|ptič|m}}, {{t+|sl|ptica|f}}
* Somalia: shimbir
* Swahili: ndege ''(kata nama 9/10)''
* Sweden: {{t+|sv|fågel|c}}
* Tagalog: ibon
* Tamazight: ⴰⴳⴹⵉⴹ (agḍiḍ) {{m}}
* Telugu: పక్షి, విహంగము, పిట్ట (piTTa)
* Thai: {{Thai|นก}} (nók), {{Thai|ปักษา}} (bpàksăa)
* Tok Pisin: pisin
* Tupinambá: gûyrá
* Turan: quş
* Turki: {{t+|tr|kuş}}
* Ukraine: птах (ptákh) {{m}}
* Urdu: {{URchar|چڑیا}} (ći.riyā) {{f}}, {{URchar|پنچھی}} (pančī) {{f}}, {{URchar|پکشی} (pakšī) {{m}}, {{URchar|پرندہ}} (parandā) {{m}}, {{URchar|پکھیرو}} (pakherū) {{m}}
* Uzbek: qush
* Venice: oseo {{m}}
* Vietnam: (con) chim
* Volapük: böd
* Wales: {{t-|cy|aderyn|m|xs=Wales}}
* Yiddish: פֿויגל (foygl) {{m}}
{{ter-bawah}}
===Tesaurus===
; Sinonim: [[manuk]], [[unggas]].
==Bahasa Banjar==
===Takrifan===
====Kata nama====
{{inti|bjn|kata kerja}}
# burung
==Bahasa Iban==
===Takrifan===
====Kata nama====
{{inti|iba|kata kerja}}
# bisik
#: {{cp|iba|Bisi peda kita burung dia?|Kalian ada tengok burung di sana?}}
==Bahasa Indonesia==
===Takrifan===
====Kata nama====
{{id-kn}}
# burung
==Bahasa Kadazandusun==
===Takrifan===
====Kata kerja====
{{inti|dtp|kata kerja}}
# [[bisik]].
#: {{ux|dtp|Au oku korongou tuni '''burung''' nu tu ologod kopio ilo yolo minsinding.
|Saya tidak mendengar bunyi '''bisik''' kamu kerana mereka bernyanyi terlalu kuat.}}
# sejenis alat bekas diikat di [[pinggang]]
===Sebutan===
* {{IPA|dtp|/ɓʊ.rʊŋ/}}
* {{penyempangan|dtp|bu|rung}}
[[File:LL-Q5317225 (dtp)-Meqqal-burung.wav|thumb|LL-Q5317225 (dtp)-Meqqal-burung]]
===Kata terbitan===
*{{l|dtp|binurung}}
*{{l|dtp|burungo'}}
*{{l|dtp|burungai}}
*{{l|dtp|binurungan}}
*{{l|dtp|koburung}}
*{{l|dtp|kobuburung}}
*{{l|dtp|murung-burung}}
*{{l|dtp|momurung}}
*{{l|dtp|momuuburung}}
*{{l|dtp|oburungan}}
*{{l|dtp|popoburung}}
*{{l|dtp|nokoburung}}
===Rujukan===
* {{R:Komoiboros DusunKadazan}}
3n2d6ioudsaewlkr38uaf4oba97hdbf
218851
218850
2025-06-20T10:01:59Z
Song GK
5715
218851
wikitext
text/x-wiki
{{wikipedia}}
{{ms}}
[[Fail:Blue Tit aka.jpg|thumb|Seekor burung.]]
===Sebutan===
* {{dewan|bu|rung}}
* {{a|Johor-Selangor}} {{IPA|ms|/buroŋ/}}
* {{a|Riau-Lingga}} {{IPA|ms|/burʊŋ/}}
* {{rima|ms|uroŋ|roŋ|oŋ}}
* {{audio|ms|ms-MY-burung.ogg|Audio (MY)}}
* {{a|Sebutan baku; Kamus Dewan Perdana}} {{IPA|ms|/bu.rung/}}
* {{audio|ms|LL-Q9237 (msa)-Hakimi97-burung.wav|Audio (MY-zsm)}}
===Terjemahan===
{{ter-atas|haiwan}}
* Afrikaan: voël
* Albania: {{t-|sq|zog|xs=Albania}}
* Arab: {{Arab|طير}} (tˁīr)
* Aragon: paxaro {{m}}
* Armenia: լժռչուն
* Azeri: quş
* Banjar: burung
* Basque: txori
* Belanda: {{t+|nl|vogel|m}}
* Bengali: পাখী
* Breton: labous {{m}}, laboused {{p}}, evn {{m}}, evned {{p}}
* Bosnia: {{t-|bs|ptica|f}}
* Bulgaria: {{t+|bg|птица|f|tr=ptitsa|sc=Cyrl}}
* Burma: ငဟက္ (hŋeʔ)
* Catalonia: au {{m}} {{penerang|kumpulan taksonomi}}, ocell {{m}} {{penerang|burung terbang}}
* Cebuano: langgam
* Cherokee: ᏥᏍᏆ (tsisqua)
* Cina: {{zh-ts|[[鳥]]|[[鸟]]}} (niăo); {{zh-ts|[[鳥類]]|[[鸟类]]}} (niăolèi); {{Hani|[[雀]]}} (què); {{zh-ts|[[雀鳥]]|[[雀鸟]]}} (quèniăo)
* Cree: pileshish, peepee
* Croatia: {{t+|hr|ptica|f}}
* Czech: {{t+|cs|pták|m}}
* Denmark: {{t+|da|fugl}}
* Erzya: нармунь (narmunj)
* Esperanto: {{t-|eo|birdo|xs=Bahasa Esperanto}}
* Estonia: {{t-|et|lind}}
* Faroe: {{t+|fo|fuglur|m|xs=Bahasa Faroe}}
* Farsi: {{FAchar|پَرَندِه}} (pærænde)
* Finland: {{t+|fi|lintu}}
* Frisia: fûgel
* Gaelik Scot: eun {{m}}
* Galicia: paxaro
* Georgia: ფრინველი (p‘rinveli)
* Jerman: {{t+|de|Vogel|m}}
* Greek,
*: Kuno: ὄρνις (ornis) {{f}}, πτηνό (ptēnó) {{n}}
*: Moden: πουλί (poulí) {{n}}, πτηνό (ptēnó) {{n}}
* Guaraní: guyra
* Gujarati: પનખિદ (pankhida)
* Guugu Yimidhirr: dyidyirr
* Hawaii: manu
* Hindi: चिड़िया (ći.riyā) {{f}}, पंछी (pančī) {{f}}, पक्षी (pakšī) {{m}}, परन्दा (parandā) {{m}}, पखेरू (pakherū) {{m}}
* Hungary: {{t+|hu|madár}}
* Ibrani: צפור (tzipor)
* Iceland: {{t+|is|fugl|m}}
* Ido: ucelo
* Indonesia: {{t+|id|burung|xs=Bahasa Indonesia}}
* Inggeris: {{t+|en|bird}}
* Inggeris Lama: {{t-|ang|fugol|xs=Bahasa Inggeris Lama}}
* Interlingua: ave
* Inuktitut: ᑎᖕᒥᐊᖅ (tingmiaq)
* Ireland: éan ''m1''
* Itali: {{t+|it|uccello|m}}
* Jepun: [[鳥]] (とり, tori)
* Kazakh: құс
* Khmer: {{KMchar|បក្សី}} (bʌksēi)
* Korea: 새 (sæ)
* Kurdi: firrinde, balinde, çivîk, çûçik, teyr, tilûr, terewîl, {{KUchar|باڵنده}}, {{KUchar|تهیر}}
* Ladino: ave, have {{f}}, pášaro, pážaro, pájaro, pásaro {{m}}
{{ter-tengah}}
* Lao: {{Laoo|ນົກ}} (nok)
* Latin: avis, -is
* Latvia: putns {{m}}
* Lithuania: paũkštis
* Macedonia: птица (ptica)
* Malagasy: vorona
* Malayalam: പക്ഷി, തടവറ, പറവ, വിഹഗം, കിളി, കുരുവി, പെണ്കുട്ടി, സ്ത്രീ, ജയില്ശിക്ഷ, പ്രത്യേകതയുള്ള വ്യക്തി
* Malta: tajra, għasfur
* Maori: {{t+|mi|manu|xs=Bahasa_Maori}}
* Mi'kmaq: jipji'j
* Mohikan: tschèchtschis
* Mongolia: {{t+|mn|шувуу|tr=šuvuu|sc=Cyrl|xs=Bahasa_Mongolia}}
* Nanticoke: piss-seeques
* Nenets: тиртя
* Nganasan: тәибәә
* Norway: {{t-|no|fugl|m}}
* Novial: fogle
* Occitan: {{italbrac|Lengadocian}} aucèl {{m}}, {{italbrac|Auvernhàs, Lemosin, Provençau}} aucèu {{m}} {{italbrac|Gascon}} ausèth {{m}}
* Ojibwe: bineshiinh
* Perancis: {{t+|fr|oiseau|m}}
* Poland: {{t+|pl|ptak|m}}
* Portugis: {{t+|pt|pássaro|m}}, {{t+|pt|ave|f}}
* Potawatomi: pnéshi
* Powhatan: tshehip
* Punjabi: ਪੰਖੀ
* Rohingya: faik
* Romania: {{t+|ro|pasăre|f}}
* Rusia: {{t+|ru|птица|f|tr=ptítsa|sc=Cyrl}}
* Samoa: manu
* Sanskrit: {{term|sc=Deva|वि|tr=ví|m}}
* Saxon Rendah: Vagel {{m}}
* Sepanyol: {{t+|es|pájaro|m}}, {{t+|es|ave|f}}
* Serbia:
*: Cyril: птица {{f}}
*: Rumi: ptica {{f}}
* Sicily: aceddu {{m}}
* Slovakia: vták {{m}}
* Slovenia: {{t+|sl|ptič|m}}, {{t+|sl|ptica|f}}
* Somalia: shimbir
* Swahili: ndege ''(kata nama 9/10)''
* Sweden: {{t+|sv|fågel|c}}
* Tagalog: ibon
* Tamazight: ⴰⴳⴹⵉⴹ (agḍiḍ) {{m}}
* Telugu: పక్షి, విహంగము, పిట్ట (piTTa)
* Thai: {{Thai|นก}} (nók), {{Thai|ปักษา}} (bpàksăa)
* Tok Pisin: pisin
* Tupinambá: gûyrá
* Turan: quş
* Turki: {{t+|tr|kuş}}
* Ukraine: птах (ptákh) {{m}}
* Urdu: {{URchar|چڑیا}} (ći.riyā) {{f}}, {{URchar|پنچھی}} (pančī) {{f}}, {{URchar|پکشی} (pakšī) {{m}}, {{URchar|پرندہ}} (parandā) {{m}}, {{URchar|پکھیرو}} (pakherū) {{m}}
* Uzbek: qush
* Venice: oseo {{m}}
* Vietnam: (con) chim
* Volapük: böd
* Wales: {{t-|cy|aderyn|m|xs=Wales}}
* Yiddish: פֿויגל (foygl) {{m}}
{{ter-bawah}}
===Tesaurus===
; Sinonim: [[manuk]], [[unggas]].
==Bahasa Banjar==
===Takrifan===
====Kata nama====
{{inti|bjn|kata nama}}
# burung
==Bahasa Iban==
===Takrifan===
====Kata nama====
{{inti|iba|kata nama}}
# bisik
#: {{cp|iba|Bisi peda kita '''burung''' dia?|Kalian ada tengok '''burung''' di sana?}}
==Bahasa Indonesia==
===Takrifan===
====Kata nama====
{{id-kn}}
# burung
==Bahasa Kadazandusun==
===Takrifan===
====Kata kerja====
{{inti|dtp|kata kerja}}
# [[bisik]].
#: {{ux|dtp|Au oku korongou tuni '''burung''' nu tu ologod kopio ilo yolo minsinding.
|Saya tidak mendengar bunyi '''bisik''' kamu kerana mereka bernyanyi terlalu kuat.}}
# sejenis alat bekas diikat di [[pinggang]]
===Sebutan===
* {{IPA|dtp|/ɓʊ.rʊŋ/}}
* {{penyempangan|dtp|bu|rung}}
[[File:LL-Q5317225 (dtp)-Meqqal-burung.wav|thumb|LL-Q5317225 (dtp)-Meqqal-burung]]
===Kata terbitan===
*{{l|dtp|binurung}}
*{{l|dtp|burungo'}}
*{{l|dtp|burungai}}
*{{l|dtp|binurungan}}
*{{l|dtp|koburung}}
*{{l|dtp|kobuburung}}
*{{l|dtp|murung-burung}}
*{{l|dtp|momurung}}
*{{l|dtp|momuuburung}}
*{{l|dtp|oburungan}}
*{{l|dtp|popoburung}}
*{{l|dtp|nokoburung}}
===Rujukan===
* {{R:Komoiboros DusunKadazan}}
2qrjqklr4agsqxh8fqru8k9ps2qf4ar
Modul:string utilities
828
11594
218836
185162
2025-06-19T22:43:20Z
Sponge2490
8927
Mengemaskini berdasarkan Module:string utilities pada 14 Jun 2025 (85118790)
218836
Scribunto
text/plain
local export = {}
local function_module = "Module:fun"
local load_module = "Module:load"
local memoize_module = "Module:memoize"
local string_char_module = "Module:string/char"
local string_charset_escape_module = "Module:string/charsetEscape"
local mw = mw
local string = string
local table = table
local ustring = mw.ustring
local byte = string.byte
local char = string.char
local concat = table.concat
local find = string.find
local format = string.format
local gmatch = string.gmatch
local gsub = string.gsub
local insert = table.insert
local len = string.len
local lower = string.lower
local match = string.match
local next = next
local require = require
local reverse = string.reverse
local select = select
local sort = table.sort
local sub = string.sub
local tonumber = tonumber
local tostring = tostring
local type = type
local ucodepoint = ustring.codepoint
local ufind = ustring.find
local ugcodepoint = ustring.gcodepoint
local ugmatch = ustring.gmatch
local ugsub = ustring.gsub
local ulower = ustring.lower
local umatch = ustring.match
local unpack = unpack or table.unpack -- Lua 5.2 compatibility
local upper = string.upper
local usub = ustring.sub
local uupper = ustring.upper
local memoize = require(memoize_module)
-- Defined below.
local codepoint
local explode_utf8
local format_fun
local get_charset
local gsplit
local pattern_escape
local pattern_simplifier
local replacement_escape
local title_case
local trim
local ucfirst
local ulen
--[==[
Loaders for functions in other modules, which overwrite themselves with the target function when called. This ensures
modules are only loaded when needed, retains the speed/convenience of locally-declared pre-loaded functions, and has no
overhead after the first call, since the target functions are called directly in any subsequent calls.
]==]
local function charset_escape(...)
charset_escape = require(string_charset_escape_module)
return charset_escape(...)
end
local function is_callable(...)
is_callable = require(function_module).is_callable
return is_callable(...)
end
local function load_data(...)
load_data = require(load_module).load_data
return load_data(...)
end
local function u(...)
u = require(string_char_module)
return u(...)
end
local function prepare_iter(str, pattern, str_lib, plain)
local callable = is_callable(pattern)
if str_lib or plain then
return pattern, #str, string, callable
elseif not callable then
local simple = pattern_simplifier(pattern)
if simple then
return simple, #str, string, false
end
end
return pattern, ulen(str), ustring, callable
end
--[==[
Returns {nil} if the input value is the empty string, or otherwise the same value.
If the input is a string and `do_trim` is set, the input value will be trimmed before returning; if the trimmed value is
the empty string, returns {nil}.
If `quote_delimiters` is set, then any outer pair of quotation marks ({' '} or {" "}) surrounding the rest of the input
string will be stripped, if present. The string will not be trimmed again, converted to {nil}, or have further quotation
marks stripped, as it exists as a way to embed spaces or the empty string in an input. Genuine quotation marks may also
be embedded this way (e.g. {"''foo''"} returns {"'foo'"}).
]==]
function export.is_not_empty(str, do_trim, quote_delimiters)
if str == "" then
return nil
elseif not (str and type(str) == "string") then
return str
elseif do_trim then
str = trim(str)
if str == "" then
return nil
end
end
return quote_delimiters and gsub(str, "^(['\"])(.*)%1$", "%2") or str
end
--[==[
Explodes a string into an array of UTF-8 characters. '''Warning''': this function assumes that the input is valid UTF-8
in order to optimize speed and memory use. Passing in an input containing non-UTF-8 byte sequences could result in
unexpected behaviour.
]==]
function export.explode_utf8(str)
local text, i = {}, 0
for ch in gmatch(str, ".[\128-\191]*") do
i = i + 1
text[i] = ch
end
return text
end
explode_utf8 = export.explode_utf8
--[==[
Returns {true} if `str` is a valid UTF-8 string. This is true if, for each character, all of the following are true:
* It has the expected number of bytes, which is determined by value of the leading byte: 1-byte characters are `0x00` to
`0x7F`, 2-byte characters start with `0xC2` to `0xDF`, 3-byte characters start with `0xE0` to `0xEF`, and 4-byte
characters start with `0xF0` to `0xF4`.
* The leading byte must not fall outside of the above ranges.
* The trailing byte(s) (if any), must be between `0x80` to `0xBF`.
* The character's codepoint must be between U+0000 (`0x00`) and U+10FFFF (`0xF4 0x8F 0xBF 0xBF`).
* The character cannot have an overlong encoding: for each byte length, the lowest theoretical encoding is equivalent to
U+0000 (e.g. `0xE0 0x80 0x80`, the lowest theoretical 3-byte encoding, is exactly equivalent to U+0000). Encodings
that use more than the minimum number of bytes are not considered valid, meaning that the first valid 3-byte
character is `0xE0 0xA0 0x80` (U+0800), and the first valid 4-byte character is `0xF0 0x90 0x80 0x80` (U+10000).
Formally, 2-byte characters have leading bytes ranging from `0xC0` to `0xDF` (rather than `0xC2` to `0xDF`), but
`0xC0 0x80` to `0xC1 0xBF` are overlong encodings, so it is simpler to say that the 2-byte range begins at `0xC2`.
If `allow_surrogates` is set, surrogates (U+D800 to U+DFFF) will be treated as valid UTF-8. Surrogates are used in
UTF-16, which encodes codepoints U+0000 to U+FFFF with 2 bytes, and codepoints from U+10000 upwards using a pair of
surrogates, which are taken together as a 4-byte unit. Since surrogates have no use in UTF-8, as it encodes higher
codepoints in a different way, they are not considered valid in UTF-8 text. However, there are limited circumstances
where they may be necessary: for instance, JSON escapes characters using the format `\u0000`, which must contain exactly
4 hexadecimal digits; under the scheme, codepoints above U+FFFF must be escaped as the equivalent pair of surrogates,
even though the text itself must be encoded in UTF-8 (e.g. U+10000 becomes `\uD800\uDC00`).
]==]
function export.isutf8(str, allow_surrogates)
for ch in gmatch(str, "[\128-\255][\128-\191]*") do
if #ch > 4 then
return false
end
local b1, b2, b3, b4 = byte(ch, 1, 4)
if not (b2 and b2 >= 0x80 and b2 <= 0xBF) then
return false -- 1-byte is always invalid, as gmatch excludes 0x00 to 0x7F
elseif not b3 then -- 2-byte
if not (b1 >= 0xC2 and b1 <= 0xDF) then -- b1 == 0xC0 or b1 == 0xC1 is overlong
return false
end
elseif not (b3 >= 0x80 and b3 <= 0xBF) then -- trailing byte
return false
elseif not b4 then -- 3-byte
if b1 > 0xEF then
return false
elseif b2 < 0xA0 then
if b1 < 0xE1 then -- b1 == 0xE0 and b2 < 0xA0 is overlong
return false
end
elseif b1 < 0xE0 or (b1 == 0xED and not allow_surrogates) then -- b1 == 0xED and b2 >= 0xA0 is a surrogate
return false
end
elseif not (b4 >= 0x80 and b4 <= 0xBF) then -- 4-byte
return false
elseif b2 < 0x90 then
if not (b1 >= 0xF1 and b1 <= 0xF4) then -- b1 == 0xF0 and b2 < 0x90 is overlong
return false
end
elseif not (b1 >= 0xF0 and b1 <= 0xF3) then -- b1 == 0xF4 and b2 >= 0x90 is too high
return false
end
end
return true
end
do
local charset_chars = {
["\0"] = "%z", ["%"] = "%%", ["-"] = "%-", ["]"] = "%]", ["^"] = "%^"
}
charset_chars.__index = charset_chars
local chars = setmetatable({
["$"] = "%$", ["("] = "%(", [")"] = "%)", ["*"] = "%*", ["+"] = "%+",
["."] = "%.", ["?"] = "%?", ["["] = "%["
}, charset_chars)
--[==[
Escapes the magic characters used in a [[mw:Extension:Scribunto/Lua reference manual#Patterns|pattern]] (Lua's
version of regular expressions): {$%()*+-.?[]^}, and converts the null character to {%z}. For example,
{"^$()%.[]*+-?\0"} becomes {"%^%$%(%)%%%.%[%]%*%+%-%?%z"}. This is necessary when constructing a pattern involving
arbitrary text (e.g. from user input).
]==]
function export.pattern_escape(str)
return (gsub(str, "[%z$%%()*+%-.?[%]^]", chars))
end
pattern_escape = export.pattern_escape
--[==[
Escapes only {%}, which is the only magic character used in replacement
[[mw:Extension:Scribunto/Lua reference manual#Patterns|patterns]] with string.gsub and mw.ustring.gsub.
]==]
function export.replacement_escape(str)
return (gsub(str, "%%", "%%%%"))
end
replacement_escape = export.replacement_escape
local function case_insensitive_char(ch)
local upper_ch = uupper(ch)
if upper_ch == ch then
ch = ulower(ch)
if ch == upper_ch then
return chars[ch] or ch
end
end
return "[" .. (charset_chars[upper_ch] or upper_ch) .. (charset_chars[ch] or ch) .. "]"
end
local function iterate(str, str_len, text, n, start, _gsub, _sub, loc1, loc2)
if not (loc1 and start <= str_len) then
-- Add final chunk and return.
n = n + 1
text[n] = _gsub(_sub(str, start), ".", chars)
return
elseif loc2 < loc1 then
if _sub == sub then
local b = byte(str, loc1)
if b and b >= 128 then
loc1 = loc1 + (b < 224 and 1 or b < 240 and 2 or 3)
end
end
n = n + 1
text[n] = _gsub(_sub(str, start, loc1), ".", chars)
start = loc1 + 1
if start > str_len then
return
end
else
-- Add chunk up to the current match.
n = n + 1
text[n] = _gsub(_sub(str, start, loc1 - 1), ".", chars)
-- Add current match.
n = n + 1
text[n] = _gsub(_sub(str, loc1, loc2), ".", case_insensitive_char)
start = loc2 + 1
end
return n, start
end
--[==[
Escapes the magic characters used in a [[mw:Extension:Scribunto/Lua reference manual#Patterns|pattern]], and makes
all characters case-insensitive. An optional pattern or find function (see {split}) may be supplied as the second
argument, the third argument (`str_lib`) forces use of the string library, while the fourth argument (`plain`) turns
any pattern matching facilities off in the optional pattern supplied.
]==]
function export.case_insensitive_pattern(str, pattern_or_func, str_lib, plain)
if pattern_or_func == nil then
return (gsub(str, str_lib and "[^\128-\255]" or ".[\128-\191]*", case_insensitive_char))
end
local text, n, start, str_len, _string, callable = {}, 0, 1
pattern_or_func, str_len, _string, callable = prepare_iter(str, pattern_or_func, str_lib, plain)
local _find, _gsub, _sub = _string.find, _string.gsub, _string.sub
if callable then
repeat
n, start = iterate(str, str_len, text, n, start, _gsub, _sub, pattern_or_func(str, start))
until not start
-- Special case if the pattern is anchored to the start: "^" always
-- anchors to the start position, not the start of the string, so get
-- around this by only attempting one match with the pattern, then match
-- the end of the string.
elseif byte(pattern_or_func) == 0x5E then -- ^
n, start = iterate(str, str_len, text, n, start, _gsub, _sub, _find(str, pattern_or_func, start, plain))
if start ~= nil then
iterate(str, str_len, text, n, start, _gsub, _sub, _find(str, "$", start, plain))
end
else
repeat
n, start = iterate(str, str_len, text, n, start, _gsub, _sub, _find(str, pattern_or_func, start, plain))
until not start
end
return concat(text)
end
end
do
local character_classes
local function get_character_classes()
character_classes, get_character_classes = {
[0x41] = true, [0x61] = true, -- Aa
[0x43] = true, [0x63] = true, -- Cc
[0x44] = true, [0x64] = true, -- Dd
[0x4C] = true, [0x6C] = true, -- Ll
[0x50] = true, [0x70] = true, -- Pp
[0x53] = true, [0x73] = true, -- Ss
[0x55] = true, [0x75] = true, -- Uu
[0x57] = true, [0x77] = true, -- Ww
[0x58] = true, [0x78] = true, -- Xx
[0x5A] = true, -- z dealt with separately.
}, nil
return character_classes
end
local function check_sets_equal(set1, set2)
local k2
for k1, v1 in next, set1 do
local v2 = set2[k1]
if v1 ~= v2 and (v2 == nil or not check_sets_equal(v1, v2)) then
return false
end
k2 = next(set2, k2)
end
return next(set2, k2) == nil
end
local function check_sets(bytes)
local key, set1, set = next(bytes)
if set1 == true then
return true
elseif not check_sets(set1) then
return false
end
while true do
key, set = next(bytes, key)
if not key then
return true
elseif not check_sets_equal(set, set1) then
return false
end
end
end
local function make_charset(range)
if #range == 1 then
return char(range[1])
end
sort(range)
local compressed, n, start = {}, 0, range[1]
for i = 1, #range do
local this, nxt = range[i], range[i + 1]
if nxt ~= this + 1 then
n = n + 1
compressed[n] = this == start and char(this) or
char(start) .. "-" .. char(this)
start = nxt
end
end
return "[" .. concat(compressed) .. "]"
end
local function parse_1_byte_charset(pattern, pos)
local ch
while true do
pos, ch = match(pattern, "()([%%%]\192-\255])", pos)
if ch == "%" then
local nxt = byte(pattern, pos + 1)
if not nxt or nxt >= 128 or (character_classes or get_character_classes())[nxt] then -- acdlpsuwxACDLPSUWXZ, but not z
return false
end
pos = pos + 2
elseif ch == "]" then
pos = pos + 1
return pos
else
return false
end
end
end
--[==[
Parses `pattern`, a ustring library pattern, and attempts to convert it into a string library pattern. If conversion
isn't possible, returns false.
]==]
function pattern_simplifier(pattern)
if type(pattern) == "number" then
return tostring(pattern)
end
local pos, capture_groups, start, n, output, ch, nxt_pos = 1, 0, 1, 0
while true do
-- FIXME: use "()([%%(.[\128-\255])[\128-\191]?[\128-\191]?[\128-\191]?()" and ensure non-UTF8 always fails.
pos, ch, nxt_pos = match(pattern, "()([%%(.[\192-\255])[\128-\191]*()", pos)
if not ch then
break
end
local nxt = byte(pattern, nxt_pos)
if ch == "%" then
if nxt == 0x62 then -- b
local nxt2, nxt3 = byte(pattern, pos + 2, pos + 3)
if not (nxt2 and nxt2 < 128 and nxt3 and nxt3 < 128) then
return false
end
pos = pos + 4
elseif nxt == 0x66 then -- f
nxt_pos = nxt_pos + 2
local nxt2, nxt3 = byte(pattern, nxt_pos - 1, nxt_pos)
-- Only possible to convert a positive %f charset which is
-- all ASCII, so use parse_1_byte_charset.
if not (nxt2 == 0x5B and nxt3 and nxt3 ~= 0x5E and nxt3 < 128) then -- [^
return false
elseif nxt3 == 0x5D then -- Initial ] is non-magic.
nxt_pos = nxt_pos + 1
end
pos = parse_1_byte_charset(pattern, nxt_pos)
if not pos then
return false
end
elseif nxt == 0x5A then -- Z
nxt = byte(pattern, nxt_pos + 1)
if nxt == 0x2A or nxt == 0x2D then -- *-
pos = pos + 3
else
if output == nil then
output = {}
end
local ins = sub(pattern, start, pos - 1) .. "[\1-\127\192-\255]"
n = n + 1
if nxt == 0x2B then -- +
output[n] = ins .. "%Z*"
pos = pos + 3
elseif nxt == 0x3F then -- ?
output[n] = ins .. "?[\128-\191]*"
pos = pos + 3
else
output[n] = ins .. "[\128-\191]*"
pos = pos + 2
end
start = pos
end
elseif not nxt or (character_classes or get_character_classes())[nxt] then -- acdlpsuwxACDLPSUWX, but not Zz
return false
-- Skip the next character if it's ASCII. Otherwise, we will
-- still need to do length checks.
else
pos = pos + (nxt < 128 and 2 or 1)
end
elseif ch == "(" then
if nxt == 0x29 or capture_groups == 32 then -- )
return false
end
capture_groups = capture_groups + 1
pos = pos + 1
elseif ch == "." then
if nxt == 0x2A or nxt == 0x2D then -- *-
pos = pos + 2
else
if output == nil then
output = {}
end
local ins = sub(pattern, start, pos - 1) .. "[^\128-\191]"
n = n + 1
if nxt == 0x2B then -- +
output[n] = ins .. ".*"
pos = pos + 2
elseif nxt == 0x3F then -- ?
output[n] = ins .. "?[\128-\191]*"
pos = pos + 2
else
output[n] = ins .. "[\128-\191]*"
pos = pos + 1
end
start = pos
end
elseif ch == "[" then
-- Fail negative charsets. TODO: 1-byte charsets should be safe.
if nxt == 0x5E then -- ^
return false
-- If the first character is "%", ch_len is determined by the
-- next one instead.
elseif nxt == 0x25 then -- %
nxt = byte(pattern, nxt_pos + 1)
elseif nxt == 0x5D then -- Initial ] is non-magic.
nxt_pos = nxt_pos + 1
end
if not nxt then
return false
end
local ch_len = nxt < 128 and 1 or nxt < 224 and 2 or nxt < 240 and 3 or 4
if ch_len == 1 then -- Single-byte charset.
pos = parse_1_byte_charset(pattern, nxt_pos)
if not pos then
return false
end
else -- Multibyte charset.
-- TODO: 1-byte chars should be safe to mix with multibyte chars. CONFIRM THIS FIRST.
local charset_pos, bytes = pos
pos = pos + 1
while true do -- TODO: non-ASCII charset ranges.
pos, ch, nxt_pos = match(pattern, "^()([^\128-\191])[\128-\191]*()", pos)
-- If escaped, get the next character. No need to
-- distinguish magic characters or character classes,
-- as they'll all fail for having the wrong length
-- anyway.
if ch == "%" then
pos, ch, nxt_pos = match(pattern, "^()([^\128-\191])[\128-\191]*()", nxt_pos)
elseif ch == "]" then
pos = nxt_pos
break
end
if not (ch and nxt_pos - pos == ch_len) then
return false
elseif bytes == nil then
bytes = {}
end
local bytes, last = bytes, nxt_pos - 1
for i = pos, last - 1 do
local b = byte(pattern, i)
local bytes_b = bytes[b]
if bytes_b == nil then
bytes_b = {}
bytes[b] = bytes_b
end
bytes[b], bytes = bytes_b, bytes_b
end
bytes[byte(pattern, last)] = true
pos = nxt_pos
end
if not pos then
return false
end
nxt = byte(pattern, pos)
if (
(nxt == 0x2A or nxt == 0x2D or nxt == 0x3F) or -- *-?
(nxt == 0x2B and ch_len > 2) or -- +
not check_sets(bytes)
) then
return false
end
local ranges, b, key, next_byte = {}, 0
repeat
key, next_byte = next(bytes)
local range, n = {key}, 1
-- Loop starts on the second iteration.
for key in next, bytes, key do
n = n + 1
range[n] = key
end
b = b + 1
ranges[b] = range
bytes = next_byte
until next_byte == true
if nxt == 0x2B then -- +
local range1, range2 = ranges[1], ranges[2]
ranges[1], ranges[3] = make_charset(range1), make_charset(range2)
local n = #range2
for i = 1, #range1 do
n = n + 1
range2[n] = range1[i]
end
ranges[2] = make_charset(range2) .. "*"
pos = pos + 1
else
for i = 1, #ranges do
ranges[i] = make_charset(ranges[i])
end
end
if output == nil then
output = {}
end
nxt = byte(pattern, pos)
n = n + 1
output[n] = sub(pattern, start, charset_pos - 1) .. concat(ranges) ..
((nxt == 0x2A or nxt == 0x2B or nxt == 0x2D or nxt == 0x3F) and "%" or "") -- following *+-? now have to be escaped
start = pos
end
elseif not nxt then
break
elseif nxt == 0x2B then -- +
if nxt_pos - pos ~= 2 then
return false
elseif output == nil then
output = {}
end
pos, nxt_pos = pos + 1, nxt_pos + 1
nxt = byte(pattern, nxt_pos)
local ch2 = sub(pattern, pos, pos)
n = n + 1
output[n] = sub(pattern, start, pos - 1) .. "[" .. ch .. ch2 .. "]*" .. ch2 ..
((nxt == 0x2A or nxt == 0x2B or nxt == 0x2D or nxt == 0x3F) and "%" or "") -- following *+-? now have to be escaped
pos, start = nxt_pos, nxt_pos
elseif nxt == 0x2A or nxt == 0x2D or nxt == 0x3F then -- *-?
return false
else
pos = nxt_pos
end
end
if start == 1 then
return pattern
end
return concat(output) .. sub(pattern, start)
end
pattern_simplifier = memoize(pattern_simplifier, true)
export.pattern_simplifier = pattern_simplifier
end
--[==[
Parses `charset`, the interior of a string or ustring library character set, and normalizes it into a string or ustring
library pattern (e.g. {"abcd-g"} becomes {"[abcd-g]"}, and {"[]"} becomes {"[[%]]"}).
The negative (`^`), range (`-`) and literal (`%`) magic characters work as normal, and character classes may be used
(e.g. `%d` and `%w`), but opening and closing square brackets are sanitized so that they behave like ordinary
characters.
]==]
function get_charset(charset)
if type(charset) == "number" then
return tostring(charset)
end
local pos, start, n, output = 1, 1, 0
if byte(charset) == 0x5E then -- ^
pos = pos + 1
end
-- FIXME: "]" is non-magic if it's the first character in a charset.
local nxt_pos, nxt
while true do
local new_pos, ch = match(charset, "()([%%%-%]])", pos)
if not ch then
break
-- Skip percent escapes. Ranges can't start with them, either.
elseif ch == "%" then
pos = new_pos + 2
else
-- If `ch` is a hyphen, get the character before iff it's at or ahead of `pos`.
if ch == "-" and new_pos > pos then
pos, nxt_pos, nxt = new_pos - 1, new_pos, ch
ch = sub(charset, pos, pos)
else
pos, nxt_pos = new_pos, new_pos + 1
nxt = sub(charset, nxt_pos, nxt_pos)
end
-- Range.
if nxt == "-" then
if output == nil then
output = {}
end
n = n + 1
output[n] = sub(charset, start, pos - 1)
nxt_pos = nxt_pos + 1
nxt = sub(charset, nxt_pos, nxt_pos)
-- Ranges fail if they end with a percent escape, so escape the hyphen to avoid undefined behaviour.
if nxt == "" or nxt == "%" then
n = n + 1
output[n] = (ch == "]" and "%]" or ch) .. "%-"
start = nxt_pos
nxt_pos = nxt_pos + 2
-- Since ranges can't contain "%]", since it's escaped, range inputs like "]-z" or "a-]" must be
-- adjusted to the character before or after, plus "%]" (e.g. "%]^-z" or "a-\\%]"). The escaped "%]" is
-- omitted if the range would be empty (i.e. if the first byte is greater than the second).
else
n = n + 1
output[n] = (ch == "]" and (byte(nxt) >= 0x5D and "%]^" or "^") or ch) .. "-" ..
(nxt == "]" and (byte(ch) <= 0x5D and "\\%]" or "\\") or nxt)
nxt_pos = nxt_pos + 1
start = nxt_pos
end
elseif ch == "-" or ch == "]" then
if output == nil then
output = {}
end
n = n + 1
output[n] = sub(charset, start, pos - 1) .. "%" .. ch
start = nxt_pos
end
pos = nxt_pos
end
end
if start == 1 then
return "[" .. charset .. "]"
end
return "[" .. concat(output) .. sub(charset, start) .. "]"
end
get_charset = memoize(get_charset, true)
export.get_charset = get_charset
function export.len(str)
return type(str) == "number" and len(str) or
#str - #gsub(str, "[^\128-\191]+", "")
end
ulen = export.len
function export.sub(str, i, j)
str, i = type(str) == "number" and tostring(str) or str, i or 1
if i < 0 or j and j < 0 then
return usub(str, i, j)
elseif j and i > j or i > #str then
return ""
end
local n, new_i = 0
for loc1, loc2 in gmatch(str, "()[^\128-\191]+()[\128-\191]*") do
n = n + loc2 - loc1
if not new_i and n >= i then
new_i = loc2 - (n - i) - 1
if not j then
return sub(str, new_i)
end
end
if j and n > j then
return sub(str, new_i, loc2 - (n - j) - 1)
end
end
return new_i and sub(str, new_i) or ""
end
do
local function _find(str, loc1, loc2, ...)
if loc1 and not match(str, "^()[^\128-\255]*$") then
-- Use raw values of loc1 and loc2 to get loc1 and the length of the match.
loc1, loc2 = ulen(sub(str, 1, loc1)), ulen(sub(str, loc1, loc2))
-- Offset length with loc1 to get loc2.
loc2 = loc1 + loc2 - 1
end
return loc1, loc2, ...
end
--[==[A version of find which uses string.find when possible, but otherwise uses mw.ustring.find.]==]
function export.find(str, pattern, init, plain)
init = init or 1
if init ~= 1 and not match(str, "^()[^\128-\255]*$") then
return ufind(str, pattern, init, plain)
elseif plain then
return _find(str, find(str, pattern, init, true))
end
local simple = pattern_simplifier(pattern)
if simple then
return _find(str, find(str, simple, init))
end
return ufind(str, pattern, init)
end
end
--[==[A version of match which uses string.match when possible, but otherwise uses mw.ustring.match.]==]
function export.match(str, pattern, init)
init = init or 1
if init ~= 1 and not match(str, "^()[^\128-\255]*$") then
return umatch(str, pattern, init)
end
local simple = pattern_simplifier(pattern)
if simple then
return match(str, simple, init)
end
return umatch(str, pattern, init)
end
--[==[A version of gmatch which uses string.gmatch when possible, but otherwise uses mw.ustring.gmatch.]==]
function export.gmatch(str, pattern)
local simple = pattern_simplifier(pattern)
if simple then
return gmatch(str, simple)
end
return ugmatch(str, pattern)
end
--[==[A version of gsub which uses string.gsub when possible, but otherwise uses mw.ustring.gsub.]==]
function export.gsub(str, pattern, repl, n)
local simple = pattern_simplifier(pattern)
if simple then
return gsub(str, simple, repl, n)
end
return ugsub(str, pattern, repl, n)
end
--[==[
Like gsub, but pattern-matching facilities are turned off, so `pattern` and `repl` (if a string) are treated as literal.
]==]
function export.plain_gsub(str, pattern, repl, n)
return gsub(str, pattern_escape(pattern), type(repl) == "string" and replacement_escape(repl) or repl, n)
end
--[==[
Reverses a UTF-8 string; equivalent to string.reverse.
]==]
function export.reverse(str)
return reverse((gsub(str, "[\192-\255][\128-\191]*", reverse)))
end
function export.char(...) -- To be moved to [[Module:string/char]].
return u(...)
end
do
local function utf8_err(func_name)
error(format("bad argument #1 to '%s' (string is not UTF-8)", func_name), 4)
end
local function get_codepoint(func_name, b1, b2, b3, b4)
if b1 <= 0x7F then
return b1, 1
elseif not (b2 and b2 >= 0x80 and b2 <= 0xBF) then
utf8_err(func_name)
elseif b1 <= 0xDF then
local cp = 0x40 * b1 + b2 - 0x3080
return cp >= 0x80 and cp or utf8_err(func_name), 2
elseif not (b3 and b3 >= 0x80 and b3 <= 0xBF) then
utf8_err(func_name)
elseif b1 <= 0xEF then
local cp = 0x1000 * b1 + 0x40 * b2 + b3 - 0xE2080
return cp >= 0x800 and cp or utf8_err(func_name), 3
elseif not (b4 and b4 >= 0x80 and b4 <= 0xBF) then
utf8_err(func_name)
end
local cp = 0x40000 * b1 + 0x1000 * b2 + 0x40 * b3 + b4 - 0x3C82080
return cp >= 0x10000 and cp <= 0x10FFFF and cp or utf8_err(func_name), 4
end
function export.codepoint(str, i, j)
if str == "" then
return -- return nothing
elseif type(str) == "number" then
return byte(str, i, j)
end
i, j = i or 1, j == -1 and #str or i or 1
if i == 1 and j == 1 then
return (get_codepoint("codepoint", byte(str, 1, 4)))
elseif i < 0 or j < 0 then
return ucodepoint(str, i, j) -- FIXME
end
local n, nb, ret, nr = 0, 1, {}, 0
while n < j do
n = n + 1
if n < i then
local b = byte(str, nb)
nb = nb + (b < 128 and 1 or b < 224 and 2 or b < 240 and 3 or 4)
else
local b1, b2, b3, b4 = byte(str, nb, nb + 3)
if not b1 then
break
end
nr = nr + 1
local add
ret[nr], add = get_codepoint("codepoint", b1, b2, b3, b4)
nb = nb + add
end
end
return unpack(ret)
end
codepoint = export.codepoint
function export.gcodepoint(str, i, j)
i, j = i or 1, j ~= -1 and j or nil
if i < 0 or j and j < 0 then
return ugcodepoint(str, i, j) -- FIXME
end
local n, nb = 1, 1
while n < i do
local b = byte(str, nb)
if not b then
break
end
nb = nb + (b < 128 and 1 or b < 224 and 2 or b < 240 and 3 or 4)
n = n + 1
end
return function()
if j and n > j then
return nil
end
n = n + 1
local b1, b2, b3, b4 = byte(str, nb, nb + 3)
if not b1 then
return nil
end
local ret, add = get_codepoint("gcodepoint", b1, b2, b3, b4)
nb = nb + add
return ret
end
end
end
do
local _ulower = ulower
--[==[A version of lower which uses string.lower when possible, but otherwise uses mw.ustring.lower.]==]
function export.lower(str)
return (match(str, "^()[^\128-\255]*$") and lower or _ulower)(str)
end
end
do
local _uupper = uupper
--[==[A version of upper which uses string.upper when possible, but otherwise uses mw.ustring.upper.]==]
function export.upper(str)
return (match(str, "^()[^\128-\255]*$") and upper or _uupper)(str)
end
end
do
local function add_captures(t, n, ...)
if ... == nil then
return
end
-- Insert any captures from the splitting pattern.
local offset, capture = n - 1, ...
while capture do
n = n + 1
t[n] = capture
capture = select(n - offset, ...)
end
return n
end
--[==[
Reimplementation of mw.text.split() that includes any capturing groups in the splitting pattern. This works like
Python's re.split() function, except that it has Lua's behavior when the split pattern is empty (i.e. advancing by
one character at a time; Python returns the whole remainder of the string). When possible, it will use the string
library, but otherwise uses the ustring library. There are two optional parameters: `str_lib` forces use of the
string library, while `plain` turns any pattern matching facilities off, treating `pattern` as literal.
In addition, `pattern` may be a custom find function (or callable table), which takes the input string and start
index as its two arguments, and must return the start and end index of the match, plus any optional captures, or nil
if there are no further matches. By default, the start index will be calculated using the ustring library, unless
`str_lib` or `plain` is set.
]==]
function export.split(str, pattern_or_func, str_lib, plain)
local iter, t, n = gsplit(str, pattern_or_func, str_lib, plain), {}, 0
repeat
n = add_captures(t, n, iter())
until n == nil
return t
end
export.capturing_split = export.split -- To be removed.
end
--[==[
Returns an iterator function, which iterates over the substrings returned by {split}. The first value returned is the
string up the splitting pattern, with any capture groups being returned as additional values on that iteration.
]==]
function export.gsplit(str, pattern_or_func, str_lib, plain)
local start, final, str_len, _string, callable = 1
pattern_or_func, str_len, _string, callable = prepare_iter(str, pattern_or_func, str_lib, plain)
local _find, _sub = _string.find, _string.sub
local function iter(loc1, loc2, ...)
-- If no match, or there is but we're past the end of the string
-- (which happens when the match is the empty string), then return
-- the final chunk.
if not loc1 then
final = true
return _sub(str, start)
end
-- Special case: If we match the empty string, then eat the
-- next character; this avoids an infinite loop, and makes
-- splitting by the empty string work the way mw.text.gsplit() does
-- (including non-adjacent empty string matches with %f). If we
-- reach the end of the string this way, set `final` to true, so we
-- don't get stuck matching the empty string at the end.
local chunk
if loc2 < loc1 then
-- If using the string library, we need to make sure we advance
-- by one UTF-8 character.
if _sub == sub then
local b = byte(str, loc1)
if b and b >= 128 then
loc1 = loc1 + (b < 224 and 1 or b < 240 and 2 or 3)
end
end
chunk = _sub(str, start, loc1)
if loc1 >= str_len then
final = true
else
start = loc1 + 1
end
-- Eat chunk up to the current match.
else
chunk = _sub(str, start, loc1 - 1)
start = loc2 + 1
end
return chunk, ...
end
if callable then
return function()
if not final then
return iter(pattern_or_func(str, start))
end
end
-- Special case if the pattern is anchored to the start: "^" always
-- anchors to the start position, not the start of the string, so get
-- around this by only attempting one match with the pattern, then match
-- the end of the string.
elseif byte(pattern_or_func) == 0x5E then -- ^
local returned
return function()
if not returned then
returned = true
return iter(_find(str, pattern_or_func, start, plain))
elseif not final then
return iter(_find(str, "$", start, plain))
end
end
end
return function()
if not final then
return iter(_find(str, pattern_or_func, start, plain))
end
end
end
gsplit = export.gsplit
function export.count(str, pattern, plain)
if plain then
return select(2, gsub(str, pattern_escape(pattern), ""))
end
local simple = pattern_simplifier(pattern)
if simple then
return select(2, gsub(str, pattern, ""))
end
return select(2, ugsub(str, pattern, ""))
end
function export.trim(str, charset, str_lib, plain)
if charset == nil then
-- "^.*%S" is the fastest trim algorithm except when strings only consist of characters to be trimmed, which are
-- very slow due to catastrophic backtracking. gsub with "^%s*" gets around this by trimming such strings to ""
-- first.
return match(gsub(str, "^%s*", ""), "^.*%S") or ""
elseif charset == "" then
return str
end
charset = plain and ("[" .. charset_escape(charset) .. "]") or get_charset(charset)
-- The pattern uses a non-greedy quantifier instead of the algorithm used for %s, because negative character sets
-- are non-trivial to compute (e.g. "[^^-z]" becomes "[%^_-z]"). Plus, if the ustring library has to be used, there
-- would be two callbacks into PHP, which is slower.
local pattern = "^" .. charset .. "*(.-)" .. charset .. "*$"
if not str_lib then
local simple = pattern_simplifier(pattern)
if not simple then
return umatch(str, pattern)
end
pattern = simple
end
return match(str, pattern)
end
trim = export.trim
do
local entities
local function get_entities()
entities, get_entities = load_data("Module:data/entities"), nil
return entities
end
local function decode_entity(hash, x, code)
if hash == "" then
return (entities or get_entities())[x .. code]
end
local cp
if x == "" then
cp = match(code, "^()%d+$") and tonumber(code)
else
cp = match(code, "^()%x+$") and tonumber(code, 16)
end
return cp and (cp <= 0xD7FF or cp >= 0xE000 and cp <= 0x10FFFF) and u(cp) or nil
end
-- Non-ASCII characters aren't valid in proper HTML named entities, but MediaWiki uses them in some custom aliases
-- which have also been included in [[Module:data/entities]].
function export.decode_entities(str)
local amp = find(str, "&", nil, true)
return amp and find(str, ";", amp, true) and gsub(str, "&(#?)([xX]?)([%w\128-\255]+);", decode_entity) or str
end
end
do
local entities
local function get_entities()
-- Memoized HTML entities (taken from mw.text.lua).
entities, get_entities = {
["\""] = """,
["&"] = "&",
["'"] = "'",
["<"] = "<",
[">"] = ">",
["\194\160"] = " ",
}, nil
return entities
end
local function encode_entity(ch)
local entity = (entities or get_entities())[ch]
if entity == nil then
local cp = codepoint(ch)
-- U+D800 to U+DFFF are surrogates, so can't be encoded as entities.
entity = cp and (cp <= 0xD7FF or cp >= 0xE000) and format("&#%d;", cp) or false
entities[ch] = entity
end
return entity or nil
end
function export.encode_entities(str, charset, str_lib, plain)
if charset == nil then
return (gsub(str, "[\"&'<>\194]\160?", entities or get_entities()))
elseif charset == "" then
return str
end
local pattern = plain and ("[" .. charset_escape(charset) .. "]") or charset == "." and charset or get_charset(charset)
if not str_lib then
local simple = pattern_simplifier(pattern)
if not simple then
return (ugsub(str, pattern, encode_entity))
end
pattern = simple
end
return (gsub(str, pattern, encode_entity))
end
end
do
local function decode_path(code)
return char(tonumber(code, 16))
end
local function decode(lead, trail)
if lead == "+" or lead == "_" then
return " " .. trail
elseif #trail == 2 then
return decode_path(trail)
end
return lead .. trail
end
function export.decode_uri(str, enctype)
enctype = enctype and upper(enctype) or "QUERY"
if enctype == "PATH" then
return find(str, "%", nil, true) and gsub(str, "%%(%x%x)", decode_path) or str
elseif enctype == "QUERY" then
return (find(str, "%", nil, true) or find(str, "+", nil, true)) and gsub(str, "([%%%+])(%x?%x?)", decode) or str
elseif enctype == "WIKI" then
return (find(str, "%", nil, true) or find(str, "_", nil, true)) and gsub(str, "([%%_])(%x?%x?)", decode) or str
end
error("bad argument #2 to 'decode_uri' (expected QUERY, PATH, or WIKI)", 2)
end
end
do
local function _remove_comments(str, pre)
local head = find(str, "<!--", nil, true)
if not head then
return str
end
local ret, n = {sub(str, 1, head - 1)}, 1
while true do
local loc = find(str, "-->", head + 4, true)
if not loc then
return pre and concat(ret) or
concat(ret) .. sub(str, head)
end
head = loc + 3
loc = find(str, "<!--", head, true)
if not loc then
return concat(ret) .. sub(str, head)
end
n = n + 1
ret[n] = sub(str, head, loc - 1)
head = loc
end
end
--[==[
Removes any HTML comments from the input text. `stage` can be one of three options:
* {"PRE"} (default) applies the method used by MediaWiki's preprocessor: all
{{code|html|<nowiki><!-- ... --></nowiki>}} pairs are removed, as well as any text after an unclosed
{{code|html|<nowiki><!--</nowiki>}}. This is generally suitable when parsing raw template or
[[mw:Parser extension tags|parser extension tag]] code. (Note, however, that the actual method used by the
preprocessor is considerably more complex and differs under certain conditions (e.g. comments inside nowiki tags);
if full accuracy is absolutely necessary, use [[Module:template parser]] instead).
* {"POST"} applies the method used to generate the final page output once all templates have been expanded: it loops
over the text, removing any {{code|html|<nowiki><!-- ... --></nowiki>}} pairs until no more are found (e.g.
{{code|html|<nowiki><!-<!-- ... -->- ... --></nowiki>}} would be fully removed), but any unclosed
{{code|html|<nowiki><!--</nowiki>}} is ignored. This is suitable for handling links embedded in template inputs,
where the {"PRE"} method will have already been applied by the native parser.
* {"BOTH"} applies {"PRE"} then {"POST"}.
]==]
function export.remove_comments(str, stage)
if not stage or stage == "PRE" then
return _remove_comments(str, true)
end
local processed = stage == "POST" and _remove_comments(str) or
stage == "BOTH" and _remove_comments(str, true) or
error("bad argument #2 to 'remove_comments' (expected PRE, POST, or BOTH)", 2)
while processed ~= str do
str = processed
processed = _remove_comments(str)
end
return str
end
end
do
local byte_escapes
local function get_byte_escapes()
byte_escapes, get_byte_escapes = load_data("Module:string utilities/data").byte_escapes, nil
return byte_escapes
end
local function escape_byte(b)
return (byte_escapes or get_byte_escapes())[b] or format("\\%03d", byte(b))
end
function export.escape_bytes(str)
return (gsub(str, ".", escape_byte))
end
end
function export.format_fun(str, fun)
return (gsub(str, "{(\\?)((\\?)[^{}]*)}", function(p1, name, p2)
if #p1 + #p2 == 1 then
return name == "op" and "{" or
name == "cl" and "}" or
error(mw.getCurrentFrame():getTitle() .. " format: unrecognized escape sequence '{\\" .. name .. "}'")
elseif fun(name) and type(fun(name)) ~= "string" then
error(mw.getCurrentFrame():getTitle() .. " format: \"" .. name .. "\" is a " .. type(fun(name)) .. ", not a string")
end
return fun(name) or error(mw.getCurrentFrame():getTitle() .. " format: \"" .. name .. "\" not found in table")
end))
end
format_fun = export.format_fun
--[==[
This function, unlike {string.format} and {mw.ustring.format}, takes just two parameters, a format string and a table,
and replaces all instances of { {param_name} } in the format string with the table's entry for {param_name}. The opening
and closing brace characters can be escaped with { {\op} } and { {\cl} }, respectively. A table entry beginning with a
slash can be escaped by doubling the initial slash.
====Examples====
* {string_utilities.format("{foo} fish, {bar} fish, {baz} fish, {quux} fish", {["foo"]="one", ["bar"]="two", ["baz"]="red", ["quux"]="blue"}) }
*: produces: {"one fish, two fish, red fish, blue fish"}
* {string_utilities.format("The set {\\op}1, 2, 3{\\cl} contains {\\\\hello} elements.", {["\\hello"]="three"})}
*: produces: {"The set {1, 2, 3} contains three elements."}
*:* Note that the single and double backslashes should be entered as double and quadruple backslashes when quoted in a literal string.
]==]
function export.format(str, tbl)
return format_fun(str, function(key)
return tbl[key]
end)
end
do
local function do_uclcfirst(str, case_func)
-- Re-case the first letter.
local first, remainder = match(str, "^(.[\128-\191]*)(.*)")
return first and (case_func(first) .. remainder) or ""
end
local function uclcfirst(str, case_func)
-- Strip off any HTML tags at the beginning. This currently does not handle comments or <ref>...</ref>
-- correctly; it's intended for text wrapped in <span> or the like, as happens when passing text through
-- [[Module:links]].
local html_at_beginning = nil
if str:match("^<") then
while true do
local html_tag, rest = str:match("^(<.->)(.*)$")
if not html_tag then
break
end
if not html_at_beginning then
html_at_beginning = {}
end
insert(html_at_beginning, html_tag)
str = rest
end
end
-- If there's a link at the beginning, re-case the first letter of the
-- link text. This pattern matches both piped and unpiped links.
-- If the link is not piped, the second capture (linktext) will be empty.
local link, linktext, remainder = match(str, "^%[%[([^|%]]+)%|?(.-)%]%](.*)$")
local retval
if link then
retval = "[[" .. link .. "|" .. do_uclcfirst(linktext ~= "" and linktext or link, case_func) .. "]]" .. remainder
else
retval = do_uclcfirst(str, case_func)
end
if html_at_beginning then
retval = concat(html_at_beginning) .. retval
end
return retval
end
--[==[
Uppercase the first character of the input string, correctly handling one-part and two-part links, optionally
surrounded by HTML tags such as `<nowiki><span>...</span></nowiki>`, possibly nested. Intended to correctly
uppercase the first character of text that may include links that have been passed through `full_link()` in
[[Module:links]] or a similar function.
]==]
function export.ucfirst(str)
return uclcfirst(str, uupper)
end
ucfirst = export.ucfirst
--[==[
Lowercase the first character of the input string, correctly handling one-part and two-part links, optionally
surrounded by HTML tags such as `<nowiki><span>...</span></nowiki>`, possibly nested. Intended to correctly
lowercase the first character of text that may include links that have been passed through `full_link()` in
[[Module:links]] or a similar function.
]==]
function export.lcfirst(str)
return uclcfirst(str, ulower)
end
--[==[Capitalizes each word of the input string. WARNING: May be broken in the presence of multiword links.]==]
function export.capitalize(str)
-- Capitalize multi-word that is separated by spaces
-- by uppercasing the first letter of each part.
return (ugsub(str, "%w+", ucfirst))
end
local function do_title_case(first, remainder)
first = uupper(first)
return remainder == "" and first or (first .. ulower(remainder))
end
--[==[
Capitalizes each word of the input string, with any further letters in each word being converted to lowercase.
]==]
function export.title_case(str)
return str == "" and "" or ugsub(str, "(%w)(%w*)", do_title_case)
end
title_case = export.title_case
--[==[
Converts the input string to {{w|Camel case|CamelCase}}. Any non-word characters are treated as breaks between
words. If `lower_first` is set, then the first character of the string will be lowercase (e.g. camelCase).
]==]
function export.camel_case(str, lower_first)
str = ugsub(str, "%W*(%w*)", title_case)
return lower_first and do_uclcfirst(str, ulower) or str
end
end
do
local function do_snake_case(nonword, word)
return nonword == "" and word or "_" .. word
end
--[==[
Converts the input string to {{w|Snake case|snake_case}}. Any non-word characters are treated as breaks between
words.
]==]
function export.snake_case(str)
return (ugsub(str, "(%W*)(%w*)", do_snake_case))
end
end
return export
ndjfpg4lokleft04xzto19wigx7fczh
218837
218836
2025-06-19T22:46:30Z
Sponge2490
8927
Membatalkan semakan [[Special:Diff/218836|218836]] oleh [[Special:Contributions/Sponge2490|Sponge2490]] ([[User talk:Sponge2490|perbincangan]]) Ralat
218837
Scribunto
text/plain
local mw = mw
local string = string
local table = table
local ustring = mw.ustring
local byte = string.byte
local char = string.char
local concat = table.concat
local find = string.find
local format = string.format
local gmatch = string.gmatch
local gsub = string.gsub
local len = string.len
local load_data = mw.loadData
local lower = string.lower
local match = string.match
local next = next
local reverse = string.reverse
local select = select
local sort = table.sort
local sub = string.sub
local toNFD = ustring.toNFD
local tonumber = tonumber
local tostring = tostring
local type = type
local ucodepoint = ustring.codepoint
local ufind = ustring.find
local ugcodepoint = ustring.gcodepoint
local ugmatch = ustring.gmatch
local ugsub = ustring.gsub
local ulower = ustring.lower
local umatch = ustring.match
local unpack = unpack
local upper = string.upper
local usub = ustring.sub
local uupper = ustring.upper
-- Defined below.
local charset_escape
local codepoint
local explode_utf8
local format_fun
local get_indefinite_article
local pattern_escape
local pattern_simplifier
local php_trim
local replacement_escape
local u
local ulen
local module_name = "string_utilities"
local export = {}
--[==[Explodes a string into an array of UTF-8 characters. '''Warning''': this function has no safety checks for non-UTF-8 byte sequences, to optimize speed and memory use. Inputs containing them therefore result in undefined behaviour.]==]
function export.explode_utf8(str)
local text, i = {}, 0
for ch in gmatch(str, ".[\128-\191]*") do
i = i + 1
text[i] = ch
end
return text
end
explode_utf8 = export.explode_utf8
do
local chars = {
["\0"] = "%z", ["$"] = "%$", ["%"] = "%%", ["("] = "%(", [")"] = "%)",
["*"] = "%*", ["+"] = "%+", ["-"] = "%-", ["."] = "%.", ["?"] = "%?",
["["] = "%[", ["]"] = "%]", ["^"] = "%^"
}
--[==[Escapes the magic characters used in [[mw:Extension:Scribunto/Lua reference manual#Patterns|patterns]] (Lua's version of regular expressions): <code>$%()*+-.?[]^</code>, and converts the null character to <code>%z</code>. For example, {{code|lua|"^$()%.[]*+-?\0"}} becomes {{code|lua|"%^%$%(%)%%%.%[%]%*%+%-%?%z"}}. This is necessary when constructing a pattern involving arbitrary text (e.g. from user input).]==]
function export.pattern_escape(str)
return (gsub(str, "[%z$%%()*+%-.?[%]^]", chars))
end
pattern_escape = export.pattern_escape
--[==[Escapes the magic characters used in [[mw:Extension:Scribunto/Lua reference manual#Patterns|pattern]] character sets: <code>%-]^</code>, and converts the null character to <code>%z</code>.]==]
function export.charset_escape(str)
return (gsub(str, "[%z%%%-%]^]", chars))
end
charset_escape = export.charset_escape
end
--[==[Escapes only <code>%</code>, which is the only magic character used in replacement [[mw:Extension:Scribunto/Lua reference manual#Patterns|patterns]] with string.gsub and mw.ustring.gsub.]==]
function export.replacement_escape(str)
return (gsub(str, "%%", "%%%%"))
end
replacement_escape = export.replacement_escape
do
local function check_sets_equal(set1, set2)
local k2
for k1, v1 in next, set1 do
local v2 = set2[k1]
if v1 ~= v2 and (v2 == nil or not check_sets_equal(v1, v2)) then
return false
end
k2 = next(set2, k2)
end
return next(set2, k2) == nil
end
local function check_sets(bytes)
local key, set1, set = next(bytes)
if set1 == true then
return true
elseif not check_sets(set1) then
return false
end
while true do
key, set = next(bytes, key)
if not key then
return true
elseif not check_sets_equal(set, set1) then
return false
end
end
end
local function make_charset(range)
if #range == 1 then
return char(range[1])
end
sort(range)
local compressed, n, start = {}, 0, range[1]
for i = 1, #range do
local this, nxt = range[i], range[i + 1]
if nxt ~= this + 1 then
n = n + 1
compressed[n] = this == start and char(this) or
char(start) .. "-" .. char(this)
start = nxt
end
end
return "[" .. concat(compressed) .. "]"
end
local function parse_1_byte_charset(pattern, pos)
while true do
local ch, nxt_pos
pos, ch, nxt_pos = match(pattern, "()([%%%]\194-\244][\128-\191]*)()", pos)
if not ch then
return false
elseif ch == "%" then
if match(pattern, "^[acdlpsuwxACDLPSUWXZ\128-\255]", nxt_pos) then
return false
end
pos = pos + 2
elseif ch == "]" then
pos = nxt_pos
return pos
else
return false
end
end
end
--[==[Parses `pattern`, a ustring library pattern, and attempts to convert it into a string library pattern. If conversion isn't possible, returns false.]==]
pattern_simplifier = require("Module:fun").memoize(function(pattern)
if type(pattern) == "number" then
return tostring(pattern)
end
local pos, captures, start, n, output = 1, 0, 1, 0
while true do
local ch, nxt_pos
pos, ch, nxt_pos = match(pattern, "()([%%(.[\194-\244][\128-\191]*)()", pos)
if not ch then
break
end
local nxt = sub(pattern, nxt_pos, nxt_pos)
if ch == "%" then
if nxt == "b" then
if not match(pattern, "^()[^\128-\255][^\128-\255]", pos + 2) then
return false
end
pos = pos + 4
elseif nxt == "f" then
pos = pos + 2
if not match(pattern, "^()%[[^^]", pos) then
return false
end
-- Only possible to convert a %f charset which is all
-- ASCII, so use parse_1_byte_charset.
pos = parse_1_byte_charset(pattern, pos)
if not pos then
return false
end
elseif nxt == "Z" then
pos = pos + 2
nxt = sub(pattern, pos, pos)
if nxt == "*" or nxt == "+" or nxt == "-" then
pos = pos + 1
else
output = output or {}
n = n + 1
if nxt == "?" then
output[n] = sub(pattern, start, pos - 3) .. "[\1-\127\194-\244]?[\128-\191]*"
pos = pos + 1
else
output[n] = sub(pattern, start, pos - 3) .. "[\1-\127\194-\244][\128-\191]*"
end
start = pos
end
elseif find("acdlpsuwxACDLPSUWX", nxt, 1, true) then
return false
-- Skip the next character if it's ASCII. Otherwise, we will
-- still need to do length checks.
else
pos = pos + (byte(nxt) < 128 and 2 or 1)
end
elseif ch == "(" then
if nxt == ")" or captures == 32 then
return false
end
captures = captures + 1
pos = pos + 1
elseif ch == "." then
if nxt == "*" or nxt == "+" or nxt == "-" then
pos = pos + 2
else
output = output or {}
n = n + 1
if nxt == "?" then
output[n] = sub(pattern, start, pos - 1) .. "[^\128-\191]?[\128-\191]*"
pos = pos + 2
else
output[n] = sub(pattern, start, pos - 1) .. "[^\128-\191][\128-\191]*"
pos = pos + 1
end
start = pos
end
elseif ch == "[" then
-- Fail negative charsets. TODO: 1-byte charsets should be safe.
if nxt == "^" then
return false
-- If the first character is "%", ch_len is determined by the
-- next one instead.
elseif nxt == "%" then
nxt_pos = nxt_pos + 1
nxt = sub(pattern, nxt_pos, nxt_pos)
end
local ch_len = #match(pattern, "^.[\128-\191]*", nxt_pos)
if ch_len == 1 then -- Single-byte charset.
pos = parse_1_byte_charset(pattern, pos + 1)
if not pos then
return false
end
else -- Multibyte charset.
local charset_pos, bytes = pos
pos = pos + 1
while true do -- TODO: non-ASCII charset ranges.
pos, ch, nxt_pos = match(pattern, "()([^\128-\191][\128-\191]*)()", pos)
if not ch then
return false
-- If escaped, get the next character. No need to
-- distinguish magic characters or character classes,
-- as they'll all fail for having the wrong length
-- anyway.
elseif ch == "%" then
pos, ch, nxt_pos = match(pattern, "()([^\128-\191][\128-\191]*)()", pos)
elseif ch == "]" then
pos = nxt_pos
break
end
if ch_len ~= #ch then
return false
end
bytes = bytes or {}
local bytes = bytes
for i = 1, ch_len - 1 do
local b = byte(ch, i, i)
bytes[b] = bytes[b] or {}
bytes = bytes[b]
end
bytes[byte(ch, -1)] = true
pos = nxt_pos
end
if not pos then
return false
end
local nxt = sub(pattern, pos, pos)
if (
(nxt == "?" or nxt == "*" or nxt == "-") or
(nxt == "+" and ch_len > 2) or
not check_sets(bytes)
) then
return false
end
local ranges, b, key, next_byte = {}, 0
repeat
key, next_byte = next(bytes)
local range, n = {key}, 1
-- Loop starts on the second iteration.
for key in next, bytes, key do
n = n + 1
range[n] = key
end
b = b + 1
ranges[b] = range
bytes = next_byte
until next_byte == true
if nxt == "+" then
local range1, range2 = ranges[1], ranges[2]
ranges[1] = make_charset(range1)
ranges[3] = make_charset(range2)
local n = #range2
for i = 1, #range1 do
n = n + 1
range2[n] = range1[i]
end
ranges[2] = make_charset(range2) .. "*"
pos = pos + 1
else
for i = 1, #ranges do
ranges[i] = make_charset(ranges[i])
end
end
output = output or {}
n = n + 1
output[n] = sub(pattern, start, charset_pos - 1) .. concat(ranges)
start = pos
end
elseif nxt == "+" then
if #ch ~= 2 then
return false
end
output = output or {}
n = n + 1
output[n] = sub(pattern, start, pos) .. "[" .. ch .. "]*" .. sub(ch, 2, 2)
pos = nxt_pos + 1
start = pos
elseif nxt == "?" or nxt == "*" or nxt == "-" then
return false
else
pos = nxt_pos
end
end
if start == 1 then
return pattern
end
return concat(output) .. sub(pattern, start)
end, true)
export.pattern_simplifier = pattern_simplifier -- For testing.
end
function export.len(str)
return type(str) == "number" and len(str) or
#str - #gsub(str, "[^\128-\191]+", "")
end
ulen = export.len
function export.sub(str, i, j)
str, i = type(str) == "number" and tostring(str) or str, i or 1
if i < 0 or j and j < 0 then
return usub(str, i, j)
elseif j and i > j or i > #str then
return ""
end
local n, new_i = 0
for loc1, loc2 in gmatch(str, "()[^\128-\191]+()[\128-\191]*") do
n = n + loc2 - loc1
if not new_i and n >= i then
new_i = loc2 - (n - i) - 1
if not j then
return sub(str, new_i)
end
end
if j and n > j then
return sub(str, new_i, loc2 - (n - j) - 1)
end
end
return new_i and sub(str, new_i) or ""
end
do
local function _find(str, loc1, loc2, ...)
if loc1 and not match(str, "^()[^\128-\255]*$") then
-- Use raw values of loc1 and loc2 to get loc1 and the length of the match.
loc1, loc2 = ulen(sub(str, 1, loc1)), ulen(sub(str, loc1, loc2))
-- Offset length with loc1 to get loc2.
loc2 = loc1 + loc2 - 1
end
return loc1, loc2, ...
end
--[==[A version of find which uses string.find when possible, but otherwise uses mw.ustring.find.]==]
function export.find(str, pattern, init, plain)
init = init or 1
if init ~= 1 and not match(str, "^()[^\128-\255]*$") then
return ufind(str, pattern, init, plain)
elseif plain then
return _find(str, find(str, pattern, init, true))
end
local simple = pattern_simplifier(pattern)
if simple then
return _find(str, find(str, simple, init))
end
return ufind(str, pattern, init)
end
end
--[==[A version of match which uses string.match when possible, but otherwise uses mw.ustring.match.]==]
function export.match(str, pattern, init)
init = init or 1
if init ~= 1 and not match(str, "^()[^\128-\255]*$") then
return umatch(str, pattern, init)
end
local simple = pattern_simplifier(pattern)
if simple then
return match(str, simple, init)
end
return umatch(str, pattern, init)
end
--[==[A version of gmatch which uses string.gmatch when possible, but otherwise uses mw.ustring.gmatch.]==]
function export.gmatch(str, pattern)
local simple = pattern_simplifier(pattern)
if simple then
return gmatch(str, simple)
end
return ugmatch(str, pattern)
end
--[==[A version of gsub which uses string.gsub when possible, but otherwise uses mw.ustring.gsub.]==]
function export.gsub(str, pattern, repl, n)
local simple = pattern_simplifier(pattern)
if simple then
return gsub(str, simple, repl, n)
end
return ugsub(str, pattern, repl, n)
end
--[==[Like gsub, but pattern-matching facilities are turned off, so `pattern` and `repl` (if a string) are treated as literal.]==]
function export.plain_gsub(str, pattern, repl, n)
return gsub(str, pattern_escape(pattern), type(repl) == "string" and replacement_escape(repl) or repl, n)
end
--[==[Reverses a UTF-8 string; equivalent to string.reverse.]==]
function export.reverse(str)
return reverse(gsub(str, "[\194-\244][\128-\191]*", reverse))
end
do
local function err(cp)
error("Codepoint " .. cp .. " is out of range: codepoints must be between 0x0 and 0x10FFFF.", 2)
end
local function utf8_char(cp)
cp = tonumber(cp)
if cp < 0 then
err(format("-0x%X", -cp))
elseif cp < 0x80 then
return char(cp)
elseif cp < 0x800 then
return char(
0xC0 + cp / 0x40,
0x80 + cp % 0x40
)
elseif cp < 0x10000 then
if cp >= 0xD800 and cp < 0xE000 then
return "?" -- mw.ustring.char returns "?" for surrogates.
end
return char(
0xE0 + cp / 0x1000,
0x80 + cp / 0x40 % 0x40,
0x80 + cp % 0x40
)
elseif cp < 0x110000 then
return char(
0xF0 + cp / 0x40000,
0x80 + cp / 0x1000 % 0x40,
0x80 + cp / 0x40 % 0x40,
0x80 + cp % 0x40
)
end
err(format("0x%X", cp))
end
function export.char(cp, ...)
if ... == nil then
return utf8_char(cp)
end
local ret = {cp, ...}
for i = 1, select("#", cp, ...) do
ret[i] = utf8_char(ret[i])
end
return concat(ret)
end
u = export.char
end
do
local function get_codepoint(b1, b2, b3, b4)
if b1 < 128 then
return b1, 1
elseif b1 < 224 then
return 0x40 * b1 + b2 - 0x3080, 2
elseif b1 < 240 then
return 0x1000 * b1 + 0x40 * b2 + b3 - 0xE2080, 3
end
return 0x40000 * b1 + 0x1000 * b2 + 0x40 * b3 + b4 - 0x3C82080, 4
end
function export.codepoint(str, i, j)
if type(str) == "number" then
return byte(str, i, j)
end
i, j = i or 1, j == -1 and #str or i or 1
if i == 1 and j == 1 then
return (get_codepoint(byte(str, 1, 4)))
elseif i < 0 or j < 0 then
return ucodepoint(str, i, j) -- FIXME
end
local n, nb, ret, nr = 0, 1, {}, 0
while n < j do
n = n + 1
if n < i then
local b = byte(str, nb)
nb = nb + (b < 128 and 1 or b < 224 and 2 or b < 240 and 3 or 4)
else
local b1, b2, b3, b4 = byte(str, nb, nb + 3)
if not b1 then
break
end
nr = nr + 1
local add
ret[nr], add = get_codepoint(b1, b2, b3, b4)
nb = nb + add
end
end
return unpack(ret)
end
codepoint = export.codepoint
function export.gcodepoint(str, i, j)
i, j = i or 1, j ~= -1 and j or nil
if i < 0 or j and j < 0 then
return ugcodepoint(str, i, j) -- FIXME
end
local n, nb = 1, 1
while n < i do
local b = byte(str, nb)
if not b then
break
end
nb = nb + (b < 128 and 1 or b < 224 and 2 or b < 240 and 3 or 4)
n = n + 1
end
return function()
if j and n > j then
return nil
end
n = n + 1
local b1, b2, b3, b4 = byte(str, nb, nb + 3)
if not b1 then
return nil
end
local ret, add = get_codepoint(b1, b2, b3, b4)
nb = nb + add
return ret
end
end
end
--[==[A version of lower which uses string.lower when possible, but otherwise uses mw.ustring.lower.]==]
function export.lower(str)
return (match(str, "^()[^\128-\255]*$") and lower or ulower)(str)
end
--[==[A version of upper which uses string.upper when possible, but otherwise uses mw.ustring.upper.]==]
function export.upper(str)
return (match(str, "^()[^\128-\255]*$") and upper or uupper)(str)
end
do
local function add_captures(text, n, ...)
-- Insert any captures from the splitting pattern.
local offset, capture = n - 1, ...
while capture do
n = n + 1
text[n] = capture
capture = select(n - offset, ...)
end
return n
end
local function iterate(str, str_len, text, n, start, _sub, loc1, loc2, ...)
if not (loc1 and start <= str_len) then
-- If no match, or there is but we're past the end of the string
-- (which happens when the match is the empty string), then add
-- the final chunk and return.
n = n + 1
text[n] = _sub(str, start)
return
elseif loc2 < loc1 then
-- Special case: If we match the empty string, then include the
-- next character; this avoids an infinite loop, and makes
-- splitting by an empty string work the way mw.text.split() does
-- (including non-adjacent empty string matches with %f). If we
-- reach the end of the string this way, return immediately, so we
-- don't get a final empty string. If using the string library, we
-- need to make sure we advance by one UTF-8 character.
if _sub == sub then
loc1 = loc1 + #match(str, "^[\128-\191]*", loc1 + 1)
end
n = n + 1
text[n] = _sub(str, start, loc1)
start = loc1 + 1
if start > str_len then
return ... and add_captures(text, n, ...) or n
end
else
-- Add chunk up to the current match.
n = n + 1
text[n] = _sub(str, start, loc1 - 1)
start = loc2 + 1
end
return (... and add_captures(text, n, ...) or n), start
end
local function _split(str, get_next, str_len, _sub, _find, func, plain)
local text, n, start = {}, 0, 1
if func then
repeat
n, start = iterate(str, str_len, text, n, start, _sub, get_next(str, start))
until not start
else
repeat
n, start = iterate(str, str_len, text, n, start, _sub, _find(str, get_next, start, plain))
until not start
end
return text
end
--[==[Reimplementation of mw.text.split() that includes any capturing groups in the splitting pattern. This works like Python's re.split() function, except that it has Lua's behavior when the split pattern is empty (i.e. advancing by one character at a time; Python returns the whole remainder of the string). When possible, it will use the string library, but otherwise uses the ustring library. There are two optional parameters: `str_lib` forces use of the string library, while `plain` turns any pattern matching facilities off, treating `pattern` as literal.
In addition, `pattern` may be a custom find function, which takes the input string and start index as its two arguments, and must return the start and end index of the match, plus any optional captures, or nil if there are no further matches. By default, the start index will be calculated using the ustring library, unless `str_lib` or `plain` is set.]==]
function export.split(str, pattern, str_lib, plain)
local func = type(pattern) == "function"
if str_lib or plain then
return _split(str, pattern, #str, sub, find, func, plain)
elseif not func then
local simple = pattern_simplifier(pattern)
if simple then
return _split(str, simple, #str, sub, find)
end
end
return _split(str, pattern, ulen(str), usub, ufind, func)
end
export.capturing_split = export.split -- To be removed.
end
do
-- TODO: merge this with export.split. Not clear how to do this while
-- maintaining the same level of performance, as gsplit is slower.
local function _split(str, pattern, str_len, _sub, _find, plain)
local start, final = 1
local function iter(loc1, loc2, ...)
-- If no match, return the final chunk.
if not loc1 then
final = true
return _sub(str, start)
end
-- Special case: If we match the empty string, then eat the
-- next character; this avoids an infinite loop, and makes
-- splitting by the empty string work the way mw.text.gsplit() does
-- (including non-adjacent empty string matches with %f). If we
-- reach the end of the string this way, set `final` to true, so we
-- don't get stuck matching the empty string at the end.
local chunk
if loc2 < loc1 then
-- If using the string library, we need to make sure we advance
-- by one UTF-8 character.
if _sub == sub then
loc1 = loc1 + #match(str, "^[\128-\191]*", loc1 + 1)
end
chunk = _sub(str, start, loc1)
if loc1 >= str_len then
final = true
else
start = loc1 + 1
end
-- Eat chunk up to the current match.
else
chunk = _sub(str, start, loc1 - 1)
start = loc2 + 1
end
return chunk, ...
end
return function()
if not final then
return iter(_find(str, pattern, start, plain))
end
return nil
end
end
function export.gsplit(str, pattern, str_lib, plain)
if str_lib or plain then
return _split(str, pattern, #str, sub, find, plain)
end
local simple = pattern_simplifier(pattern)
if simple then
return _split(str, simple, #str, sub, find)
end
return _split(str, pattern, ulen(str), usub, ufind)
end
end
function export.trim(str, charset)
if not charset then
return match(str, "^()%s*$") and "" or match(str, "^%s*(.*%S)")
elseif match(charset, "^()[^\128-\255]*$") then
return match(str, "^()[" .. charset .. "]*$") and "" or match(str, "^[" .. charset .. "]*(.*[^" .. charset .. "])")
end
return umatch(str, "^[" .. charset .. "]*(.-)[" .. charset .. "]*$")
end
do
local entities
local function decode_numeric_entity(code, pattern, base)
local cp = match(code, pattern) and tonumber(code, base)
return cp and cp < 0x110000 and u(cp) or nil
end
local function decode_entity(hash, x, code)
if hash == "#" then
return x == "" and decode_numeric_entity(code, "^%d+$") or
decode_numeric_entity(code, "^%x+$", 16)
end
entities = entities or load_data("Module:data/entities")
return entities[x .. code]
end
-- Non-ASCII characters aren't valid in proper HTML named entities, but MediaWiki uses them in some custom aliases which have also been included in [[Module:data/entities]].
function export.decode_entities(str)
return find(str, "&", 1, true) and
gsub(str, "&(#?)([xX]?)([%w\128-\255]+);", decode_entity) or str
end
end
do
local html_entities
local function encode_entity(ch)
local entity = html_entities[ch]
if entity then
return entity
end
entity = "&#" .. codepoint(ch) .. ";"
html_entities[ch] = entity
return entity
end
function export.encode_entities(str, charset, str_lib, plain)
-- Memoized HTML entities (taken from mw.text.lua).
html_entities = html_entities or {
["\""] = """,
["&"] = "&",
["'"] = "'",
["<"] = "<",
[">"] = ">",
["\194\160"] = " ",
}
if not charset then
return (gsub(str, "[\"&'<>\194]\160?", html_entities))
elseif plain then
return (gsub(str, "[" .. charset_escape(charset) .. "]", encode_entity))
elseif str_lib then
if not match(charset, "^()[^\128-\255]*$") then
error("Cannot use the string library with a character set that contains a character with a codepoint above U+007F.")
end
return (gsub(str, "[" .. charset .. "]", encode_entity))
end
local pattern = charset and "[" .. charset .. "]"
local simple = pattern_simplifier(pattern)
if simple then
return (gsub(str, simple, encode_entity))
end
return (ugsub(str, pattern, encode_entity))
end
end
do
local function decode_path(code)
return char(tonumber(code, 16))
end
local function decode(lead, trail)
if lead == "+" or lead == "_" then
return " " .. trail
elseif #trail == 2 then
return decode_path(trail)
end
return lead .. trail
end
function export.decode_uri(str, enctype)
enctype = enctype and upper(enctype) or "QUERY"
if enctype == "PATH" then
return find(str, "%", 1, true) and
gsub(str, "%%(%x%x)", decode_path) or str
elseif enctype == "QUERY" then
return (find(str, "%", 1, true) or find(str, "+", 1, true)) and
gsub(str, "([%%%+])(%x?%x?)", decode) or str
elseif enctype == "WIKI" then
return (find(str, "%", 1, true) or find(str, "_", 1, true)) and
gsub(str, "([%%_])(%x?%x?)", decode) or str
end
error("bad argument #2 to \"decode_uri\" (expected QUERY, PATH, or WIKI)", 2)
end
end
do
local function _remove_comments(str, pre)
local head = find(str, "<!--", 1, true)
if not head then
return str
end
local ret, n = {sub(str, 1, head - 1)}, 1
while true do
local loc = find(str, "-->", head + 4, true)
if not loc then
return pre and concat(ret) or
concat(ret) .. sub(str, head)
end
head = loc + 3
loc = find(str, "<!--", head, true)
if not loc then
return concat(ret) .. sub(str, head)
end
n = n + 1
ret[n] = sub(str, head, loc - 1)
head = loc
end
end
--[==[Removes any HTML comments from the input text. `stage` can be one of three options:
* {{lua|"PRE"}} (default) applies the method used by MediaWiki's preprocessor: all {{code||<nowiki><!-- ... --></nowiki>}} pairs are removed, as well as any text after an unclosed {{code||<nowiki><!--</nowiki>}}. This is generally suitable when parsing raw template or [[mw:Parser extension tags|parser extension tag]] code. (Note, however, that the actual method used by the preprocessor is considerably more complex and differs under certain conditions (e.g. comments inside nowiki tags); if full accuracy is absolutely necessary, use [[Module:template parser]] instead).
* {{lua|"POST"}} applies the method used to generate the final page output once all templates have been expanded: it loops over the text, removing any {{code||<nowiki><!-- ... --></nowiki>}} pairs until no more are found (e.g. {{code||<nowiki><!-<!-- ... -->- ... --></nowiki>}} would be fully removed), but any unclosed {{code||<nowiki><!--</nowiki>}} is ignored. This is suitable for handling links embedded in template inputs, where the {{lua|"PRE"}} method will have already been applied by the native parser.
* {{lua|"BOTH"}} applies {{lua|"PRE"}} then {{lua|"POST"}}.]==]
function export.remove_comments(str, stage)
if not stage or stage == "PRE" then
return _remove_comments(str, true)
end
local processed = stage == "POST" and _remove_comments(str) or
stage == "BOTH" and _remove_comments(str, true) or
error("bad argument #2 to \"remove_comments\" (expected PRE, POST, or BOTH)", 2)
while processed ~= str do
str = processed
processed = _remove_comments(str)
end
return str
end
end
--[==[Lua equivalent of PHP's {{code|php|trim($string)}}, which trims {{code|lua|"\0"}}, {{code|lua|"\t"}}, {{code|lua|"\n"}}, {{code|lua|"\v"}}, {{code|lua|"\r"}} and {{code|lua|" "}}. This is useful when dealing with template parameters, since the native parser trims them like this.]==]
function export.php_trim(str)
return match(str, "%f[^%z\t\n\v\r ].*%f[%z\t\n\v\r ]") or ""
end
php_trim = export.php_trim
--[==[Takes a parameter name as an input, and returns the Scribunto-normalized form (i.e. the key that that parameter would have in a {{code|lua|frame.args}} table). For example, {{code|lua|"1"}} is normalized to {{code|lua|1}} (a number), and {{code|lua|" foo "}} is normalized to {{code|lua|"foo"}}. If the input is not a string, it is returned unchanged.
After being trimmed with {{code|lua|export.php_trim}}, strings are converted to numbers if:
# They are integers, with no decimals (2.0) or leading zeroes (02).
# They are ≤ 2{{sup|53}} and ≥ -2{{sup|53}}.
# For positive values, they do not have a leading {{code|lua|+}} sign.]==]
function export.scribunto_param_key(key)
if type(key) ~= "string" then
return key
end
key = php_trim(key)
if match(key, "^-?[1-9]%d*$") then
local num = tonumber(key)
-- Lua integers are only accurate to 2^53 - 1, so we have to specifically check for 2^53 and -2^53, since 2^53 == 2^53 + 1 evaluates to true.
return (
num <= 9007199254740991 and num >= -9007199254740991 or
key == "9007199254740992" or
key == "-9007199254740992"
) and num or key
elseif key == "0" then
return 0
end
return key
end
do
local byte_escapes
local function escape_byte(b)
return byte_escapes[b] or format("\\%03d", byte(b))
end
function export.escape_bytes(str)
byte_escapes = byte_escapes or load_data("Module:string utilities/data").byte_escapes
return (gsub(str, ".", escape_byte))
end
end
function export.format_fun(str, fun)
return (gsub(str, "{(\\?)((\\?)[^{}]*)}", function(p1, name, p2)
if #p1 + #p2 == 1 then
return name == "op" and "{" or
name == "cl" and "}" or
error(module_name .. ".format: unrecognized escape sequence '{\\" .. name .. "}'")
elseif fun(name) and type(fun(name)) ~= "string" then
error(module_name .. ".format: \"" .. name .. "\" is a " .. type(fun(name)) .. ", not a string")
end
return fun(name) or error(module_name .. ".format: \"" .. name .. "\" not found in table")
end))
end
format_fun = export.format_fun
--[==[This function, unlike {{code|lua|string.format}} and {{code|lua|mw.ustring.format}}, takes just two parameters—a format string and a table—and replaces all instances of {{code|lua|{param_name}}} in the format string with the table's entry for {{code|lua|param_name}}. The opening and closing brace characters can be escaped with <code>{\op}</code> and <code>{\cl}</code>, respectively. A table entry beginning with a slash can be escaped by doubling the initial slash.
====Examples====
* {{code|lua|2=string_utilities.format("{foo} fish, {bar} fish, {baz} fish, {quux} fish", {["foo"]="one", ["bar"]="two", ["baz"]="red", ["quux"]="blue"})}}
*: produces: {{code|lua|"one fish, two fish, red fish, blue fish"}}
* {{code|lua|2=string_utilities.format("The set {\\op}1, 2, 3{\\cl} contains {\\\\hello} elements.", {["\\hello"]="three"})}}
*: produces: {{code|lua|"The set {1, 2, 3} contains three elements."}}
*:* Note that the single and double backslashes should be entered as double and quadruple backslashes when quoted in a literal string.]==]
function export.format(str, tbl)
return format_fun(str, function(key)
return tbl[key]
end)
end
do
local function do_uclcfirst(str, case_func)
-- Actual function to re-case of the first letter.
local first_letter = case_func(match(str, "^.[\128-\191]*") or "")
return first_letter .. sub(str, #first_letter + 1)
end
local function uclcfirst(str, case_func)
-- If there's a link at the beginning, re-case the first letter of the
-- link text. This pattern matches both piped and unpiped links.
-- If the link is not piped, the second capture (linktext) will be empty.
local link, linktext, remainder = match(str, "^%[%[([^|%]]+)%|?(.-)%]%](.*)$")
if link then
return "[[" .. link .. "|" .. do_uclcfirst(linktext ~= "" and linktext or link, case_func) .. "]]" .. remainder
end
return do_uclcfirst(str, case_func)
end
function export.ucfirst(str)
return uclcfirst(str, uupper)
end
function export.lcfirst(str)
return uclcfirst(str, ulower)
end
local function capitalize(w)
return uclcfirst(w, uupper)
end
--[==[Capitalize each word of a string. WARNING: May be broken in the presence of multiword links.]==]
function export.capitalize(str)
if type(str) == "table" then
-- allow calling from a template
str = str.args[1]
end
-- Capitalize multi-word that is separated by spaces
-- by uppercasing the first letter of each part.
-- I assume nobody will input all CAP text.
return (ugsub(str, "%S+", capitalize))
end
end
function export.pluralize(str) -- To be removed once all calling modules have been changed to call Module:en-utilities directly.
return require("Module:en-utilities").pluralize(str)
end
do
local function do_singularize(str) -- (not applicable to Malay Wiktionary)
local sing = match(str, "^(.-)$")
if sing then
return sing .. ""
end
-- Handle cases like "[[parish]]es" (not applicable to Malay Wiktionary)
return match(str, "^(.-[cs]h%]*)$") or -- not -zhes
-- Handle cases like "[[box]]es" (not applicable to Malay Wiktionary)
match(str, "^(.-x%]*)$") or -- not -ses or -zes
-- Handle regular plurals (not applicable to Malay Wiktionary)
match(str, "^(.-)$") or
-- Otherwise, return input
str
end
local function collapse_link(link, linktext)
if link == linktext then
return "[[" .. link .. "]]"
end
return "[[" .. link .. "|" .. linktext .. "]]"
end
--[==[
Singularize a word in a smart fashion, according to normal English rules. Works analogously to {pluralize()}.
'''NOTE''': This doesn't always work as well as {pluralize()}. Beware. It will mishandle cases like "passes" -> "passe", "eyries" -> "eyry".
# If word ends in -ies, replace -ies with -y.
# If the word ends in -xes, -shes, -ches, remove -es. [Does not affect -ses, cf. "houses", "impasses".]
# Otherwise, remove -s.
This handles links correctly:
# If a piped link, change the second part appropriately. Collapse the link to a simple link if both parts end up the same.
# If a non-piped link, singularize the link.
# A link like "[[parish]]es" will be handled correctly because the code that checks for -shes etc. allows ] characters between the
'sh' etc. and final -es.
]==]
function export.singularize(str)
if type(str) == "table" then
-- allow calling from a template
str = str.args[1]
end
-- Check for a link. This pattern matches both piped and unpiped links.
-- If the link is not piped, the second capture (linktext) will be empty.
local beginning, link, linktext = match(str, "^(.*)%[%[([^|%]]+)%|?(.-)%]%]$")
if not link then
return do_singularize(str)
elseif linktext ~= "" then
return beginning .. collapse_link(link, do_singularize(linktext))
end
return beginning .. "[[" .. do_singularize(link) .. "]]"
end
end
--[==[
Return the appropriate indefinite article to prefix to `str`. Correctly handles links and capitalized text.
Does not correctly handle words like [[union]], [[uniform]] and [[university]] that take "a" despite beginning with
a 'u'. The returned article will have its first letter capitalized if `ucfirst` is specified, otherwise lowercase.
]==]
function export.get_indefinite_article(str, ucfirst)
str = str or ""
local is_vowel = false
-- If there's a link at the beginning, examine the first letter of the
-- link text. This pattern matches both piped and unpiped links.
-- If the link is not piped, the second capture (linktext) will be empty.
local link, linktext = match(str, "^%[%[([^|%]]+)%|?(.-)%]%]")
if link then
is_vowel = find(linktext ~= "" and linktext or link, "^[AEIOUaeiou]")
else
is_vowel = find(str, "^[AEIOUaeiou]")
end
return is_vowel and (ucfirst and "An" or "an") or (ucfirst and "A" or "a")
end
get_indefinite_article = export.get_indefinite_article
--[==[
Prefix `text` with the appropriate indefinite article to prefix to `text`. Correctly handles links and capitalized
text. Does not correctly handle words like [[union]], [[uniform]] and [[university]] that take "a" despite beginning
with a 'u'. The returned article will have its first letter capitalized if `ucfirst` is specified, otherwise lowercase.
]==]
function export.add_indefinite_article(text, ucfirst)
return get_indefinite_article(text, ucfirst) .. " " .. text
end
return export
p2bd29sdmm5onk4gw6hipjam6fp958v
kata seerti
0
24347
218852
186824
2025-06-20T11:46:54Z
2001:D08:EA:81E2:E89B:5E9D:5AD:7F2A
Dibenci
218852
wikitext
text/x-wiki
di benci
== Bahasa Melayu ==
{{Wikipedia}}
=== Takrifan ===
==== Kata nama ====
{{ms-kn|j=کات سأرتي}}
# Perkataan-perkataan yang memiliki [[makna]] yang [[sama]]; [[sinonim]].
=== Sebutan ===
* {{dewan|ka|ta||se|er|ti}}
=== Pautan luar ===
* {{R:PRPM}}
{{C|ms|Semantik}}
6eyhideo6spw3wlz0srdbnqwfyo3o1r
Modul:data/entities
828
41384
218835
155268
2025-06-19T22:39:25Z
Sponge2490
8927
Mengemaskini berdasarkan Module:data/entities pada 17 Disember 2023 (77232189)
218835
Scribunto
text/plain
return {
aacute = "\195\161", -- á
Aacute = "\195\129", -- Á
abreve = "\196\131", -- ă
Abreve = "\196\130", -- Ă
ac = "\226\136\190", -- ∾
acd = "\226\136\191", -- ∿
acE = "\226\136\190\204\179", -- ∾̳
acirc = "\195\162", -- â
Acirc = "\195\130", -- Â
acute = "\194\180", -- ´
acy = "\208\176", -- а
Acy = "\208\144", -- А
aelig = "\195\166", -- æ
AElig = "\195\134", -- Æ
af = "\226\129\161", -- [function application]
afr = "\240\157\148\158", -- 𝔞
Afr = "\240\157\148\132", -- 𝔄
agrave = "\195\160", -- à
Agrave = "\195\128", -- À
alefsym = "\226\132\181", -- ℵ
aleph = "\226\132\181", -- ℵ
alpha = "\206\177", -- α
Alpha = "\206\145", -- Α
amacr = "\196\129", -- ā
Amacr = "\196\128", -- Ā
amalg = "\226\168\191", -- ⨿
amp = "\38", -- &
AMP = "\38", -- &
["and"] = "\226\136\167", -- ∧
And = "\226\169\147", -- ⩓
andand = "\226\169\149", -- ⩕
andd = "\226\169\156", -- ⩜
andslope = "\226\169\152", -- ⩘
andv = "\226\169\154", -- ⩚
ang = "\226\136\160", -- ∠
ange = "\226\166\164", -- ⦤
angle = "\226\136\160", -- ∠
angmsd = "\226\136\161", -- ∡
angmsdaa = "\226\166\168", -- ⦨
angmsdab = "\226\166\169", -- ⦩
angmsdac = "\226\166\170", -- ⦪
angmsdad = "\226\166\171", -- ⦫
angmsdae = "\226\166\172", -- ⦬
angmsdaf = "\226\166\173", -- ⦭
angmsdag = "\226\166\174", -- ⦮
angmsdah = "\226\166\175", -- ⦯
angrt = "\226\136\159", -- ∟
angrtvb = "\226\138\190", -- ⊾
angrtvbd = "\226\166\157", -- ⦝
angsph = "\226\136\162", -- ∢
angst = "\195\133", -- Å
angzarr = "\226\141\188", -- ⍼
aogon = "\196\133", -- ą
Aogon = "\196\132", -- Ą
aopf = "\240\157\149\146", -- 𝕒
Aopf = "\240\157\148\184", -- 𝔸
ap = "\226\137\136", -- ≈
apacir = "\226\169\175", -- ⩯
ape = "\226\137\138", -- ≊
apE = "\226\169\176", -- ⩰
apid = "\226\137\139", -- ≋
apos = "\39", -- '
ApplyFunction = "\226\129\161", -- [function application]
approx = "\226\137\136", -- ≈
approxeq = "\226\137\138", -- ≊
aring = "\195\165", -- å
Aring = "\195\133", -- Å
ascr = "\240\157\146\182", -- 𝒶
Ascr = "\240\157\146\156", -- 𝒜
Assign = "\226\137\148", -- ≔
ast = "\42", -- *
asymp = "\226\137\136", -- ≈
asympeq = "\226\137\141", -- ≍
atilde = "\195\163", -- ã
Atilde = "\195\131", -- Ã
auml = "\195\164", -- ä
Auml = "\195\132", -- Ä
awconint = "\226\136\179", -- ∳
awint = "\226\168\145", -- ⨑
backcong = "\226\137\140", -- ≌
backepsilon = "\207\182", -- ϶
backprime = "\226\128\181", -- ‵
backsim = "\226\136\189", -- ∽
backsimeq = "\226\139\141", -- ⋍
Backslash = "\226\136\150", -- ∖
Barv = "\226\171\167", -- ⫧
barvee = "\226\138\189", -- ⊽
barwed = "\226\140\133", -- ⌅
Barwed = "\226\140\134", -- ⌆
barwedge = "\226\140\133", -- ⌅
bbrk = "\226\142\181", -- ⎵
bbrktbrk = "\226\142\182", -- ⎶
bcong = "\226\137\140", -- ≌
bcy = "\208\177", -- б
Bcy = "\208\145", -- Б
bdquo = "\226\128\158", -- „
becaus = "\226\136\181", -- ∵
because = "\226\136\181", -- ∵
Because = "\226\136\181", -- ∵
bemptyv = "\226\166\176", -- ⦰
bepsi = "\207\182", -- ϶
bernou = "\226\132\172", -- ℬ
Bernoullis = "\226\132\172", -- ℬ
beta = "\206\178", -- β
Beta = "\206\146", -- Β
beth = "\226\132\182", -- ℶ
between = "\226\137\172", -- ≬
bfr = "\240\157\148\159", -- 𝔟
Bfr = "\240\157\148\133", -- 𝔅
bigcap = "\226\139\130", -- ⋂
bigcirc = "\226\151\175", -- ◯
bigcup = "\226\139\131", -- ⋃
bigodot = "\226\168\128", -- ⨀
bigoplus = "\226\168\129", -- ⨁
bigotimes = "\226\168\130", -- ⨂
bigsqcup = "\226\168\134", -- ⨆
bigstar = "\226\152\133", -- ★
bigtriangledown = "\226\150\189", -- ▽
bigtriangleup = "\226\150\179", -- △
biguplus = "\226\168\132", -- ⨄
bigvee = "\226\139\129", -- ⋁
bigwedge = "\226\139\128", -- ⋀
bkarow = "\226\164\141", -- ⤍
blacklozenge = "\226\167\171", -- ⧫
blacksquare = "\226\150\170", -- ▪
blacktriangle = "\226\150\180", -- ▴
blacktriangledown = "\226\150\190", -- ▾
blacktriangleleft = "\226\151\130", -- ◂
blacktriangleright = "\226\150\184", -- ▸
blank = "\226\144\163", -- ␣
blk12 = "\226\150\146", -- ▒
blk14 = "\226\150\145", -- ░
blk34 = "\226\150\147", -- ▓
block = "\226\150\136", -- █
bne = "\61\226\131\165", -- =⃥
bnequiv = "\226\137\161\226\131\165", -- ≡⃥
bnot = "\226\140\144", -- ⌐
bNot = "\226\171\173", -- ⫭
bopf = "\240\157\149\147", -- 𝕓
Bopf = "\240\157\148\185", -- 𝔹
bot = "\226\138\165", -- ⊥
bottom = "\226\138\165", -- ⊥
bowtie = "\226\139\136", -- ⋈
boxbox = "\226\167\137", -- ⧉
boxdl = "\226\148\144", -- ┐
boxdL = "\226\149\149", -- ╕
boxDl = "\226\149\150", -- ╖
boxDL = "\226\149\151", -- ╗
boxdr = "\226\148\140", -- ┌
boxdR = "\226\149\146", -- ╒
boxDr = "\226\149\147", -- ╓
boxDR = "\226\149\148", -- ╔
boxh = "\226\148\128", -- ─
boxH = "\226\149\144", -- ═
boxhd = "\226\148\172", -- ┬
boxhD = "\226\149\165", -- ╥
boxHd = "\226\149\164", -- ╤
boxHD = "\226\149\166", -- ╦
boxhu = "\226\148\180", -- ┴
boxhU = "\226\149\168", -- ╨
boxHu = "\226\149\167", -- ╧
boxHU = "\226\149\169", -- ╩
boxminus = "\226\138\159", -- ⊟
boxplus = "\226\138\158", -- ⊞
boxtimes = "\226\138\160", -- ⊠
boxul = "\226\148\152", -- ┘
boxuL = "\226\149\155", -- ╛
boxUl = "\226\149\156", -- ╜
boxUL = "\226\149\157", -- ╝
boxur = "\226\148\148", -- └
boxuR = "\226\149\152", -- ╘
boxUr = "\226\149\153", -- ╙
boxUR = "\226\149\154", -- ╚
boxv = "\226\148\130", -- │
boxV = "\226\149\145", -- ║
boxvh = "\226\148\188", -- ┼
boxvH = "\226\149\170", -- ╪
boxVh = "\226\149\171", -- ╫
boxVH = "\226\149\172", -- ╬
boxvl = "\226\148\164", -- ┤
boxvL = "\226\149\161", -- ╡
boxVl = "\226\149\162", -- ╢
boxVL = "\226\149\163", -- ╣
boxvr = "\226\148\156", -- ├
boxvR = "\226\149\158", -- ╞
boxVr = "\226\149\159", -- ╟
boxVR = "\226\149\160", -- ╠
bprime = "\226\128\181", -- ‵
breve = "\203\152", -- ˘
Breve = "\203\152", -- ˘
brvbar = "\194\166", -- ¦
bscr = "\240\157\146\183", -- 𝒷
Bscr = "\226\132\172", -- ℬ
bsemi = "\226\129\143", -- ⁏
bsim = "\226\136\189", -- ∽
bsime = "\226\139\141", -- ⋍
bsol = "\92", -- \
bsolb = "\226\167\133", -- ⧅
bsolhsub = "\226\159\136", -- ⟈
bull = "\226\128\162", -- •
bullet = "\226\128\162", -- •
bump = "\226\137\142", -- ≎
bumpe = "\226\137\143", -- ≏
bumpE = "\226\170\174", -- ⪮
bumpeq = "\226\137\143", -- ≏
Bumpeq = "\226\137\142", -- ≎
cacute = "\196\135", -- ć
Cacute = "\196\134", -- Ć
cap = "\226\136\169", -- ∩
Cap = "\226\139\146", -- ⋒
capand = "\226\169\132", -- ⩄
capbrcup = "\226\169\137", -- ⩉
capcap = "\226\169\139", -- ⩋
capcup = "\226\169\135", -- ⩇
capdot = "\226\169\128", -- ⩀
CapitalDifferentialD = "\226\133\133", -- ⅅ
caps = "\226\136\169\239\184\128", -- ∩︀
caret = "\226\129\129", -- ⁁
caron = "\203\135", -- ˇ
Cayleys = "\226\132\173", -- ℭ
ccaps = "\226\169\141", -- ⩍
ccaron = "\196\141", -- č
Ccaron = "\196\140", -- Č
ccedil = "\195\167", -- ç
Ccedil = "\195\135", -- Ç
ccirc = "\196\137", -- ĉ
Ccirc = "\196\136", -- Ĉ
Cconint = "\226\136\176", -- ∰
ccups = "\226\169\140", -- ⩌
ccupssm = "\226\169\144", -- ⩐
cdot = "\196\139", -- ċ
Cdot = "\196\138", -- Ċ
cedil = "\194\184", -- ¸
Cedilla = "\194\184", -- ¸
cemptyv = "\226\166\178", -- ⦲
cent = "\194\162", -- ¢
centerdot = "\194\183", -- ·
CenterDot = "\194\183", -- ·
cfr = "\240\157\148\160", -- 𝔠
Cfr = "\226\132\173", -- ℭ
chcy = "\209\135", -- ч
CHcy = "\208\167", -- Ч
check = "\226\156\147", -- ✓
checkmark = "\226\156\147", -- ✓
chi = "\207\135", -- χ
Chi = "\206\167", -- Χ
cir = "\226\151\139", -- ○
circ = "\203\134", -- ˆ
circeq = "\226\137\151", -- ≗
circlearrowleft = "\226\134\186", -- ↺
circlearrowright = "\226\134\187", -- ↻
circledast = "\226\138\155", -- ⊛
circledcirc = "\226\138\154", -- ⊚
circleddash = "\226\138\157", -- ⊝
CircleDot = "\226\138\153", -- ⊙
circledR = "\194\174", -- ®
circledS = "\226\147\136", -- Ⓢ
CircleMinus = "\226\138\150", -- ⊖
CirclePlus = "\226\138\149", -- ⊕
CircleTimes = "\226\138\151", -- ⊗
cire = "\226\137\151", -- ≗
cirE = "\226\167\131", -- ⧃
cirfnint = "\226\168\144", -- ⨐
cirmid = "\226\171\175", -- ⫯
cirscir = "\226\167\130", -- ⧂
ClockwiseContourIntegral = "\226\136\178", -- ∲
CloseCurlyDoubleQuote = "\226\128\157", -- ”
CloseCurlyQuote = "\226\128\153", -- ’
clubs = "\226\153\163", -- ♣
clubsuit = "\226\153\163", -- ♣
colon = "\58", -- :
Colon = "\226\136\183", -- ∷
colone = "\226\137\148", -- ≔
Colone = "\226\169\180", -- ⩴
coloneq = "\226\137\148", -- ≔
comma = "\44", -- ,
commat = "\64", -- @
comp = "\226\136\129", -- ∁
compfn = "\226\136\152", -- ∘
complement = "\226\136\129", -- ∁
complexes = "\226\132\130", -- ℂ
cong = "\226\137\133", -- ≅
congdot = "\226\169\173", -- ⩭
Congruent = "\226\137\161", -- ≡
conint = "\226\136\174", -- ∮
Conint = "\226\136\175", -- ∯
ContourIntegral = "\226\136\174", -- ∮
copf = "\240\157\149\148", -- 𝕔
Copf = "\226\132\130", -- ℂ
coprod = "\226\136\144", -- ∐
Coproduct = "\226\136\144", -- ∐
copy = "\194\169", -- ©
COPY = "\194\169", -- ©
copysr = "\226\132\151", -- ℗
CounterClockwiseContourIntegral = "\226\136\179", -- ∳
crarr = "\226\134\181", -- ↵
cross = "\226\156\151", -- ✗
Cross = "\226\168\175", -- ⨯
cscr = "\240\157\146\184", -- 𝒸
Cscr = "\240\157\146\158", -- 𝒞
csub = "\226\171\143", -- ⫏
csube = "\226\171\145", -- ⫑
csup = "\226\171\144", -- ⫐
csupe = "\226\171\146", -- ⫒
ctdot = "\226\139\175", -- ⋯
cudarrl = "\226\164\184", -- ⤸
cudarrr = "\226\164\181", -- ⤵
cuepr = "\226\139\158", -- ⋞
cuesc = "\226\139\159", -- ⋟
cularr = "\226\134\182", -- ↶
cularrp = "\226\164\189", -- ⤽
cup = "\226\136\170", -- ∪
Cup = "\226\139\147", -- ⋓
cupbrcap = "\226\169\136", -- ⩈
cupcap = "\226\169\134", -- ⩆
CupCap = "\226\137\141", -- ≍
cupcup = "\226\169\138", -- ⩊
cupdot = "\226\138\141", -- ⊍
cupor = "\226\169\133", -- ⩅
cups = "\226\136\170\239\184\128", -- ∪︀
curarr = "\226\134\183", -- ↷
curarrm = "\226\164\188", -- ⤼
curlyeqprec = "\226\139\158", -- ⋞
curlyeqsucc = "\226\139\159", -- ⋟
curlyvee = "\226\139\142", -- ⋎
curlywedge = "\226\139\143", -- ⋏
curren = "\194\164", -- ¤
curvearrowleft = "\226\134\182", -- ↶
curvearrowright = "\226\134\183", -- ↷
cuvee = "\226\139\142", -- ⋎
cuwed = "\226\139\143", -- ⋏
cwconint = "\226\136\178", -- ∲
cwint = "\226\136\177", -- ∱
cylcty = "\226\140\173", -- ⌭
dagger = "\226\128\160", -- †
Dagger = "\226\128\161", -- ‡
daleth = "\226\132\184", -- ℸ
darr = "\226\134\147", -- ↓
dArr = "\226\135\147", -- ⇓
Darr = "\226\134\161", -- ↡
dash = "\226\128\144", -- ‐
dashv = "\226\138\163", -- ⊣
Dashv = "\226\171\164", -- ⫤
dbkarow = "\226\164\143", -- ⤏
dblac = "\203\157", -- ˝
dcaron = "\196\143", -- ď
Dcaron = "\196\142", -- Ď
dcy = "\208\180", -- д
Dcy = "\208\148", -- Д
dd = "\226\133\134", -- ⅆ
DD = "\226\133\133", -- ⅅ
ddagger = "\226\128\161", -- ‡
ddarr = "\226\135\138", -- ⇊
DDotrahd = "\226\164\145", -- ⤑
ddotseq = "\226\169\183", -- ⩷
deg = "\194\176", -- °
Del = "\226\136\135", -- ∇
delta = "\206\180", -- δ
Delta = "\206\148", -- Δ
demptyv = "\226\166\177", -- ⦱
dfisht = "\226\165\191", -- ⥿
dfr = "\240\157\148\161", -- 𝔡
Dfr = "\240\157\148\135", -- 𝔇
dHar = "\226\165\165", -- ⥥
dharl = "\226\135\131", -- ⇃
dharr = "\226\135\130", -- ⇂
DiacriticalAcute = "\194\180", -- ´
DiacriticalDot = "\203\153", -- ˙
DiacriticalDoubleAcute = "\203\157", -- ˝
DiacriticalGrave = "\96", -- `
DiacriticalTilde = "\203\156", -- ˜
diam = "\226\139\132", -- ⋄
diamond = "\226\139\132", -- ⋄
Diamond = "\226\139\132", -- ⋄
diamondsuit = "\226\153\166", -- ♦
diams = "\226\153\166", -- ♦
die = "\194\168", -- ¨
DifferentialD = "\226\133\134", -- ⅆ
digamma = "\207\157", -- ϝ
disin = "\226\139\178", -- ⋲
div = "\195\183", -- ÷
divide = "\195\183", -- ÷
divideontimes = "\226\139\135", -- ⋇
divonx = "\226\139\135", -- ⋇
djcy = "\209\146", -- ђ
DJcy = "\208\130", -- Ђ
dlcorn = "\226\140\158", -- ⌞
dlcrop = "\226\140\141", -- ⌍
dollar = "\36", -- $
dopf = "\240\157\149\149", -- 𝕕
Dopf = "\240\157\148\187", -- 𝔻
dot = "\203\153", -- ˙
Dot = "\194\168", -- ¨
DotDot = "\226\131\156", -- ⃜
doteq = "\226\137\144", -- ≐
doteqdot = "\226\137\145", -- ≑
DotEqual = "\226\137\144", -- ≐
dotminus = "\226\136\184", -- ∸
dotplus = "\226\136\148", -- ∔
dotsquare = "\226\138\161", -- ⊡
doublebarwedge = "\226\140\134", -- ⌆
DoubleContourIntegral = "\226\136\175", -- ∯
DoubleDot = "\194\168", -- ¨
DoubleDownArrow = "\226\135\147", -- ⇓
DoubleLeftArrow = "\226\135\144", -- ⇐
DoubleLeftRightArrow = "\226\135\148", -- ⇔
DoubleLeftTee = "\226\171\164", -- ⫤
DoubleLongLeftArrow = "\226\159\184", -- ⟸
DoubleLongLeftRightArrow = "\226\159\186", -- ⟺
DoubleLongRightArrow = "\226\159\185", -- ⟹
DoubleRightArrow = "\226\135\146", -- ⇒
DoubleRightTee = "\226\138\168", -- ⊨
DoubleUpArrow = "\226\135\145", -- ⇑
DoubleUpDownArrow = "\226\135\149", -- ⇕
DoubleVerticalBar = "\226\136\165", -- ∥
downarrow = "\226\134\147", -- ↓
Downarrow = "\226\135\147", -- ⇓
DownArrow = "\226\134\147", -- ↓
DownArrowBar = "\226\164\147", -- ⤓
DownArrowUpArrow = "\226\135\181", -- ⇵
DownBreve = "\204\145", -- ̑
downdownarrows = "\226\135\138", -- ⇊
downharpoonleft = "\226\135\131", -- ⇃
downharpoonright = "\226\135\130", -- ⇂
DownLeftRightVector = "\226\165\144", -- ⥐
DownLeftTeeVector = "\226\165\158", -- ⥞
DownLeftVector = "\226\134\189", -- ↽
DownLeftVectorBar = "\226\165\150", -- ⥖
DownRightTeeVector = "\226\165\159", -- ⥟
DownRightVector = "\226\135\129", -- ⇁
DownRightVectorBar = "\226\165\151", -- ⥗
DownTee = "\226\138\164", -- ⊤
DownTeeArrow = "\226\134\167", -- ↧
drbkarow = "\226\164\144", -- ⤐
drcorn = "\226\140\159", -- ⌟
drcrop = "\226\140\140", -- ⌌
dscr = "\240\157\146\185", -- 𝒹
Dscr = "\240\157\146\159", -- 𝒟
dscy = "\209\149", -- ѕ
DScy = "\208\133", -- Ѕ
dsol = "\226\167\182", -- ⧶
dstrok = "\196\145", -- đ
Dstrok = "\196\144", -- Đ
dtdot = "\226\139\177", -- ⋱
dtri = "\226\150\191", -- ▿
dtrif = "\226\150\190", -- ▾
duarr = "\226\135\181", -- ⇵
duhar = "\226\165\175", -- ⥯
dwangle = "\226\166\166", -- ⦦
dzcy = "\209\159", -- џ
DZcy = "\208\143", -- Џ
dzigrarr = "\226\159\191", -- ⟿
eacute = "\195\169", -- é
Eacute = "\195\137", -- É
easter = "\226\169\174", -- ⩮
ecaron = "\196\155", -- ě
Ecaron = "\196\154", -- Ě
ecir = "\226\137\150", -- ≖
ecirc = "\195\170", -- ê
Ecirc = "\195\138", -- Ê
ecolon = "\226\137\149", -- ≕
ecy = "\209\141", -- э
Ecy = "\208\173", -- Э
eDDot = "\226\169\183", -- ⩷
edot = "\196\151", -- ė
eDot = "\226\137\145", -- ≑
Edot = "\196\150", -- Ė
ee = "\226\133\135", -- ⅇ
efDot = "\226\137\146", -- ≒
efr = "\240\157\148\162", -- 𝔢
Efr = "\240\157\148\136", -- 𝔈
eg = "\226\170\154", -- ⪚
egrave = "\195\168", -- è
Egrave = "\195\136", -- È
egs = "\226\170\150", -- ⪖
egsdot = "\226\170\152", -- ⪘
el = "\226\170\153", -- ⪙
Element = "\226\136\136", -- ∈
elinters = "\226\143\167", -- ⏧
ell = "\226\132\147", -- ℓ
els = "\226\170\149", -- ⪕
elsdot = "\226\170\151", -- ⪗
emacr = "\196\147", -- ē
Emacr = "\196\146", -- Ē
empty = "\226\136\133", -- ∅
emptyset = "\226\136\133", -- ∅
EmptySmallSquare = "\226\151\187", -- ◻
emptyv = "\226\136\133", -- ∅
EmptyVerySmallSquare = "\226\150\171", -- ▫
emsp = "\226\128\131", -- [em space]
emsp13 = "\226\128\132", -- [three-per-em space]
emsp14 = "\226\128\133", -- [four-per-em space]
eng = "\197\139", -- ŋ
ENG = "\197\138", -- Ŋ
ensp = "\226\128\130", -- [en space]
eogon = "\196\153", -- ę
Eogon = "\196\152", -- Ę
eopf = "\240\157\149\150", -- 𝕖
Eopf = "\240\157\148\188", -- 𝔼
epar = "\226\139\149", -- ⋕
eparsl = "\226\167\163", -- ⧣
eplus = "\226\169\177", -- ⩱
epsi = "\206\181", -- ε
epsilon = "\206\181", -- ε
Epsilon = "\206\149", -- Ε
epsiv = "\207\181", -- ϵ
eqcirc = "\226\137\150", -- ≖
eqcolon = "\226\137\149", -- ≕
eqsim = "\226\137\130", -- ≂
eqslantgtr = "\226\170\150", -- ⪖
eqslantless = "\226\170\149", -- ⪕
Equal = "\226\169\181", -- ⩵
equals = "\61", -- =
EqualTilde = "\226\137\130", -- ≂
equest = "\226\137\159", -- ≟
Equilibrium = "\226\135\140", -- ⇌
equiv = "\226\137\161", -- ≡
equivDD = "\226\169\184", -- ⩸
eqvparsl = "\226\167\165", -- ⧥
erarr = "\226\165\177", -- ⥱
erDot = "\226\137\147", -- ≓
escr = "\226\132\175", -- ℯ
Escr = "\226\132\176", -- ℰ
esdot = "\226\137\144", -- ≐
esim = "\226\137\130", -- ≂
Esim = "\226\169\179", -- ⩳
eta = "\206\183", -- η
Eta = "\206\151", -- Η
eth = "\195\176", -- ð
ETH = "\195\144", -- Ð
euml = "\195\171", -- ë
Euml = "\195\139", -- Ë
euro = "\226\130\172", -- €
excl = "\33", -- !
exist = "\226\136\131", -- ∃
Exists = "\226\136\131", -- ∃
expectation = "\226\132\176", -- ℰ
exponentiale = "\226\133\135", -- ⅇ
ExponentialE = "\226\133\135", -- ⅇ
fallingdotseq = "\226\137\146", -- ≒
fcy = "\209\132", -- ф
Fcy = "\208\164", -- Ф
female = "\226\153\128", -- ♀
ffilig = "\239\172\131", -- ffi
fflig = "\239\172\128", -- ff
ffllig = "\239\172\132", -- ffl
ffr = "\240\157\148\163", -- 𝔣
Ffr = "\240\157\148\137", -- 𝔉
filig = "\239\172\129", -- fi
FilledSmallSquare = "\226\151\188", -- ◼
FilledVerySmallSquare = "\226\150\170", -- ▪
fjlig = "\102\106", -- fj
flat = "\226\153\173", -- ♭
fllig = "\239\172\130", -- fl
fltns = "\226\150\177", -- ▱
fnof = "\198\146", -- ƒ
fopf = "\240\157\149\151", -- 𝕗
Fopf = "\240\157\148\189", -- 𝔽
forall = "\226\136\128", -- ∀
ForAll = "\226\136\128", -- ∀
fork = "\226\139\148", -- ⋔
forkv = "\226\171\153", -- ⫙
Fouriertrf = "\226\132\177", -- ℱ
fpartint = "\226\168\141", -- ⨍
frac12 = "\194\189", -- ½
frac13 = "\226\133\147", -- ⅓
frac14 = "\194\188", -- ¼
frac15 = "\226\133\149", -- ⅕
frac16 = "\226\133\153", -- ⅙
frac18 = "\226\133\155", -- ⅛
frac23 = "\226\133\148", -- ⅔
frac25 = "\226\133\150", -- ⅖
frac34 = "\194\190", -- ¾
frac35 = "\226\133\151", -- ⅗
frac38 = "\226\133\156", -- ⅜
frac45 = "\226\133\152", -- ⅘
frac56 = "\226\133\154", -- ⅚
frac58 = "\226\133\157", -- ⅝
frac78 = "\226\133\158", -- ⅞
frasl = "\226\129\132", -- ⁄
frown = "\226\140\162", -- ⌢
fscr = "\240\157\146\187", -- 𝒻
Fscr = "\226\132\177", -- ℱ
gacute = "\199\181", -- ǵ
gamma = "\206\179", -- γ
Gamma = "\206\147", -- Γ
gammad = "\207\157", -- ϝ
Gammad = "\207\156", -- Ϝ
gap = "\226\170\134", -- ⪆
gbreve = "\196\159", -- ğ
Gbreve = "\196\158", -- Ğ
Gcedil = "\196\162", -- Ģ
gcirc = "\196\157", -- ĝ
Gcirc = "\196\156", -- Ĝ
gcy = "\208\179", -- г
Gcy = "\208\147", -- Г
gdot = "\196\161", -- ġ
Gdot = "\196\160", -- Ġ
ge = "\226\137\165", -- ≥
gE = "\226\137\167", -- ≧
gel = "\226\139\155", -- ⋛
gEl = "\226\170\140", -- ⪌
geq = "\226\137\165", -- ≥
geqq = "\226\137\167", -- ≧
geqslant = "\226\169\190", -- ⩾
ges = "\226\169\190", -- ⩾
gescc = "\226\170\169", -- ⪩
gesdot = "\226\170\128", -- ⪀
gesdoto = "\226\170\130", -- ⪂
gesdotol = "\226\170\132", -- ⪄
gesl = "\226\139\155\239\184\128", -- ⋛︀
gesles = "\226\170\148", -- ⪔
gfr = "\240\157\148\164", -- 𝔤
Gfr = "\240\157\148\138", -- 𝔊
gg = "\226\137\171", -- ≫
Gg = "\226\139\153", -- ⋙
ggg = "\226\139\153", -- ⋙
gimel = "\226\132\183", -- ℷ
gjcy = "\209\147", -- ѓ
GJcy = "\208\131", -- Ѓ
gl = "\226\137\183", -- ≷
gla = "\226\170\165", -- ⪥
glE = "\226\170\146", -- ⪒
glj = "\226\170\164", -- ⪤
gnap = "\226\170\138", -- ⪊
gnapprox = "\226\170\138", -- ⪊
gne = "\226\170\136", -- ⪈
gnE = "\226\137\169", -- ≩
gneq = "\226\170\136", -- ⪈
gneqq = "\226\137\169", -- ≩
gnsim = "\226\139\167", -- ⋧
gopf = "\240\157\149\152", -- 𝕘
Gopf = "\240\157\148\190", -- 𝔾
grave = "\96", -- `
GreaterEqual = "\226\137\165", -- ≥
GreaterEqualLess = "\226\139\155", -- ⋛
GreaterFullEqual = "\226\137\167", -- ≧
GreaterGreater = "\226\170\162", -- ⪢
GreaterLess = "\226\137\183", -- ≷
GreaterSlantEqual = "\226\169\190", -- ⩾
GreaterTilde = "\226\137\179", -- ≳
gscr = "\226\132\138", -- ℊ
Gscr = "\240\157\146\162", -- 𝒢
gsim = "\226\137\179", -- ≳
gsime = "\226\170\142", -- ⪎
gsiml = "\226\170\144", -- ⪐
gt = "\62", -- >
Gt = "\226\137\171", -- ≫
GT = "\62", -- >
gtcc = "\226\170\167", -- ⪧
gtcir = "\226\169\186", -- ⩺
gtdot = "\226\139\151", -- ⋗
gtlPar = "\226\166\149", -- ⦕
gtquest = "\226\169\188", -- ⩼
gtrapprox = "\226\170\134", -- ⪆
gtrarr = "\226\165\184", -- ⥸
gtrdot = "\226\139\151", -- ⋗
gtreqless = "\226\139\155", -- ⋛
gtreqqless = "\226\170\140", -- ⪌
gtrless = "\226\137\183", -- ≷
gtrsim = "\226\137\179", -- ≳
gvertneqq = "\226\137\169\239\184\128", -- ≩︀
gvnE = "\226\137\169\239\184\128", -- ≩︀
Hacek = "\203\135", -- ˇ
hairsp = "\226\128\138", -- [hair space]
half = "\194\189", -- ½
hamilt = "\226\132\139", -- ℋ
hardcy = "\209\138", -- ъ
HARDcy = "\208\170", -- Ъ
harr = "\226\134\148", -- ↔
hArr = "\226\135\148", -- ⇔
harrcir = "\226\165\136", -- ⥈
harrw = "\226\134\173", -- ↭
Hat = "\94", -- ^
hbar = "\226\132\143", -- ℏ
hcirc = "\196\165", -- ĥ
Hcirc = "\196\164", -- Ĥ
hearts = "\226\153\165", -- ♥
heartsuit = "\226\153\165", -- ♥
hellip = "\226\128\166", -- …
hercon = "\226\138\185", -- ⊹
hfr = "\240\157\148\165", -- 𝔥
Hfr = "\226\132\140", -- ℌ
HilbertSpace = "\226\132\139", -- ℋ
hksearow = "\226\164\165", -- ⤥
hkswarow = "\226\164\166", -- ⤦
hoarr = "\226\135\191", -- ⇿
homtht = "\226\136\187", -- ∻
hookleftarrow = "\226\134\169", -- ↩
hookrightarrow = "\226\134\170", -- ↪
hopf = "\240\157\149\153", -- 𝕙
Hopf = "\226\132\141", -- ℍ
horbar = "\226\128\149", -- ―
HorizontalLine = "\226\148\128", -- ─
hscr = "\240\157\146\189", -- 𝒽
Hscr = "\226\132\139", -- ℋ
hslash = "\226\132\143", -- ℏ
hstrok = "\196\167", -- ħ
Hstrok = "\196\166", -- Ħ
HumpDownHump = "\226\137\142", -- ≎
HumpEqual = "\226\137\143", -- ≏
hybull = "\226\129\131", -- ⁃
hyphen = "\226\128\144", -- ‐
iacute = "\195\173", -- í
Iacute = "\195\141", -- Í
ic = "\226\129\163", -- [invisible separator]
icirc = "\195\174", -- î
Icirc = "\195\142", -- Î
icy = "\208\184", -- и
Icy = "\208\152", -- И
Idot = "\196\176", -- İ
iecy = "\208\181", -- е
IEcy = "\208\149", -- Е
iexcl = "\194\161", -- ¡
iff = "\226\135\148", -- ⇔
ifr = "\240\157\148\166", -- 𝔦
Ifr = "\226\132\145", -- ℑ
igrave = "\195\172", -- ì
Igrave = "\195\140", -- Ì
ii = "\226\133\136", -- ⅈ
iiiint = "\226\168\140", -- ⨌
iiint = "\226\136\173", -- ∭
iinfin = "\226\167\156", -- ⧜
iiota = "\226\132\169", -- ℩
ijlig = "\196\179", -- ij
IJlig = "\196\178", -- IJ
Im = "\226\132\145", -- ℑ
imacr = "\196\171", -- ī
Imacr = "\196\170", -- Ī
image = "\226\132\145", -- ℑ
ImaginaryI = "\226\133\136", -- ⅈ
imagline = "\226\132\144", -- ℐ
imagpart = "\226\132\145", -- ℑ
imath = "\196\177", -- ı
imof = "\226\138\183", -- ⊷
imped = "\198\181", -- Ƶ
Implies = "\226\135\146", -- ⇒
["in"] = "\226\136\136", -- ∈
incare = "\226\132\133", -- ℅
infin = "\226\136\158", -- ∞
infintie = "\226\167\157", -- ⧝
inodot = "\196\177", -- ı
int = "\226\136\171", -- ∫
Int = "\226\136\172", -- ∬
intcal = "\226\138\186", -- ⊺
integers = "\226\132\164", -- ℤ
Integral = "\226\136\171", -- ∫
intercal = "\226\138\186", -- ⊺
Intersection = "\226\139\130", -- ⋂
intlarhk = "\226\168\151", -- ⨗
intprod = "\226\168\188", -- ⨼
InvisibleComma = "\226\129\163", -- [invisible separator]
InvisibleTimes = "\226\129\162", -- [invisible times]
iocy = "\209\145", -- ё
IOcy = "\208\129", -- Ё
iogon = "\196\175", -- į
Iogon = "\196\174", -- Į
iopf = "\240\157\149\154", -- 𝕚
Iopf = "\240\157\149\128", -- 𝕀
iota = "\206\185", -- ι
Iota = "\206\153", -- Ι
iprod = "\226\168\188", -- ⨼
iquest = "\194\191", -- ¿
iscr = "\240\157\146\190", -- 𝒾
Iscr = "\226\132\144", -- ℐ
isin = "\226\136\136", -- ∈
isindot = "\226\139\181", -- ⋵
isinE = "\226\139\185", -- ⋹
isins = "\226\139\180", -- ⋴
isinsv = "\226\139\179", -- ⋳
isinv = "\226\136\136", -- ∈
it = "\226\129\162", -- [invisible times]
itilde = "\196\169", -- ĩ
Itilde = "\196\168", -- Ĩ
iukcy = "\209\150", -- і
Iukcy = "\208\134", -- І
iuml = "\195\175", -- ï
Iuml = "\195\143", -- Ï
jcirc = "\196\181", -- ĵ
Jcirc = "\196\180", -- Ĵ
jcy = "\208\185", -- й
Jcy = "\208\153", -- Й
jfr = "\240\157\148\167", -- 𝔧
Jfr = "\240\157\148\141", -- 𝔍
jmath = "\200\183", -- ȷ
jopf = "\240\157\149\155", -- 𝕛
Jopf = "\240\157\149\129", -- 𝕁
jscr = "\240\157\146\191", -- 𝒿
Jscr = "\240\157\146\165", -- 𝒥
jsercy = "\209\152", -- ј
Jsercy = "\208\136", -- Ј
jukcy = "\209\148", -- є
Jukcy = "\208\132", -- Є
kappa = "\206\186", -- κ
Kappa = "\206\154", -- Κ
kappav = "\207\176", -- ϰ
kcedil = "\196\183", -- ķ
Kcedil = "\196\182", -- Ķ
kcy = "\208\186", -- к
Kcy = "\208\154", -- К
kfr = "\240\157\148\168", -- 𝔨
Kfr = "\240\157\148\142", -- 𝔎
kgreen = "\196\184", -- ĸ
khcy = "\209\133", -- х
KHcy = "\208\165", -- Х
kjcy = "\209\156", -- ќ
KJcy = "\208\140", -- Ќ
kopf = "\240\157\149\156", -- 𝕜
Kopf = "\240\157\149\130", -- 𝕂
kscr = "\240\157\147\128", -- 𝓀
Kscr = "\240\157\146\166", -- 𝒦
lAarr = "\226\135\154", -- ⇚
lacute = "\196\186", -- ĺ
Lacute = "\196\185", -- Ĺ
laemptyv = "\226\166\180", -- ⦴
lagran = "\226\132\146", -- ℒ
lambda = "\206\187", -- λ
Lambda = "\206\155", -- Λ
lang = "\226\159\168", -- ⟨
Lang = "\226\159\170", -- ⟪
langd = "\226\166\145", -- ⦑
langle = "\226\159\168", -- ⟨
lap = "\226\170\133", -- ⪅
Laplacetrf = "\226\132\146", -- ℒ
laquo = "\194\171", -- «
larr = "\226\134\144", -- ←
lArr = "\226\135\144", -- ⇐
Larr = "\226\134\158", -- ↞
larrb = "\226\135\164", -- ⇤
larrbfs = "\226\164\159", -- ⤟
larrfs = "\226\164\157", -- ⤝
larrhk = "\226\134\169", -- ↩
larrlp = "\226\134\171", -- ↫
larrpl = "\226\164\185", -- ⤹
larrsim = "\226\165\179", -- ⥳
larrtl = "\226\134\162", -- ↢
lat = "\226\170\171", -- ⪫
latail = "\226\164\153", -- ⤙
lAtail = "\226\164\155", -- ⤛
late = "\226\170\173", -- ⪭
lates = "\226\170\173\239\184\128", -- ⪭︀
lbarr = "\226\164\140", -- ⤌
lBarr = "\226\164\142", -- ⤎
lbbrk = "\226\157\178", -- ❲
lbrace = "\123", -- {
lbrack = "\91", -- [
lbrke = "\226\166\139", -- ⦋
lbrksld = "\226\166\143", -- ⦏
lbrkslu = "\226\166\141", -- ⦍
lcaron = "\196\190", -- ľ
Lcaron = "\196\189", -- Ľ
lcedil = "\196\188", -- ļ
Lcedil = "\196\187", -- Ļ
lceil = "\226\140\136", -- ⌈
lcub = "\123", -- {
lcy = "\208\187", -- л
Lcy = "\208\155", -- Л
ldca = "\226\164\182", -- ⤶
ldquo = "\226\128\156", -- “
ldquor = "\226\128\158", -- „
ldrdhar = "\226\165\167", -- ⥧
ldrushar = "\226\165\139", -- ⥋
ldsh = "\226\134\178", -- ↲
le = "\226\137\164", -- ≤
lE = "\226\137\166", -- ≦
LeftAngleBracket = "\226\159\168", -- ⟨
leftarrow = "\226\134\144", -- ←
Leftarrow = "\226\135\144", -- ⇐
LeftArrow = "\226\134\144", -- ←
LeftArrowBar = "\226\135\164", -- ⇤
LeftArrowRightArrow = "\226\135\134", -- ⇆
leftarrowtail = "\226\134\162", -- ↢
LeftCeiling = "\226\140\136", -- ⌈
LeftDoubleBracket = "\226\159\166", -- ⟦
LeftDownTeeVector = "\226\165\161", -- ⥡
LeftDownVector = "\226\135\131", -- ⇃
LeftDownVectorBar = "\226\165\153", -- ⥙
LeftFloor = "\226\140\138", -- ⌊
leftharpoondown = "\226\134\189", -- ↽
leftharpoonup = "\226\134\188", -- ↼
leftleftarrows = "\226\135\135", -- ⇇
leftrightarrow = "\226\134\148", -- ↔
Leftrightarrow = "\226\135\148", -- ⇔
LeftRightArrow = "\226\134\148", -- ↔
leftrightarrows = "\226\135\134", -- ⇆
leftrightharpoons = "\226\135\139", -- ⇋
leftrightsquigarrow = "\226\134\173", -- ↭
LeftRightVector = "\226\165\142", -- ⥎
LeftTee = "\226\138\163", -- ⊣
LeftTeeArrow = "\226\134\164", -- ↤
LeftTeeVector = "\226\165\154", -- ⥚
leftthreetimes = "\226\139\139", -- ⋋
LeftTriangle = "\226\138\178", -- ⊲
LeftTriangleBar = "\226\167\143", -- ⧏
LeftTriangleEqual = "\226\138\180", -- ⊴
LeftUpDownVector = "\226\165\145", -- ⥑
LeftUpTeeVector = "\226\165\160", -- ⥠
LeftUpVector = "\226\134\191", -- ↿
LeftUpVectorBar = "\226\165\152", -- ⥘
LeftVector = "\226\134\188", -- ↼
LeftVectorBar = "\226\165\146", -- ⥒
leg = "\226\139\154", -- ⋚
lEg = "\226\170\139", -- ⪋
leq = "\226\137\164", -- ≤
leqq = "\226\137\166", -- ≦
leqslant = "\226\169\189", -- ⩽
les = "\226\169\189", -- ⩽
lescc = "\226\170\168", -- ⪨
lesdot = "\226\169\191", -- ⩿
lesdoto = "\226\170\129", -- ⪁
lesdotor = "\226\170\131", -- ⪃
lesg = "\226\139\154\239\184\128", -- ⋚︀
lesges = "\226\170\147", -- ⪓
lessapprox = "\226\170\133", -- ⪅
lessdot = "\226\139\150", -- ⋖
lesseqgtr = "\226\139\154", -- ⋚
lesseqqgtr = "\226\170\139", -- ⪋
LessEqualGreater = "\226\139\154", -- ⋚
LessFullEqual = "\226\137\166", -- ≦
LessGreater = "\226\137\182", -- ≶
lessgtr = "\226\137\182", -- ≶
LessLess = "\226\170\161", -- ⪡
lesssim = "\226\137\178", -- ≲
LessSlantEqual = "\226\169\189", -- ⩽
LessTilde = "\226\137\178", -- ≲
lfisht = "\226\165\188", -- ⥼
lfloor = "\226\140\138", -- ⌊
lfr = "\240\157\148\169", -- 𝔩
Lfr = "\240\157\148\143", -- 𝔏
lg = "\226\137\182", -- ≶
lgE = "\226\170\145", -- ⪑
lHar = "\226\165\162", -- ⥢
lhard = "\226\134\189", -- ↽
lharu = "\226\134\188", -- ↼
lharul = "\226\165\170", -- ⥪
lhblk = "\226\150\132", -- ▄
ljcy = "\209\153", -- љ
LJcy = "\208\137", -- Љ
ll = "\226\137\170", -- ≪
Ll = "\226\139\152", -- ⋘
llarr = "\226\135\135", -- ⇇
llcorner = "\226\140\158", -- ⌞
Lleftarrow = "\226\135\154", -- ⇚
llhard = "\226\165\171", -- ⥫
lltri = "\226\151\186", -- ◺
lmidot = "\197\128", -- ŀ
Lmidot = "\196\191", -- Ŀ
lmoust = "\226\142\176", -- ⎰
lmoustache = "\226\142\176", -- ⎰
lnap = "\226\170\137", -- ⪉
lnapprox = "\226\170\137", -- ⪉
lne = "\226\170\135", -- ⪇
lnE = "\226\137\168", -- ≨
lneq = "\226\170\135", -- ⪇
lneqq = "\226\137\168", -- ≨
lnsim = "\226\139\166", -- ⋦
loang = "\226\159\172", -- ⟬
loarr = "\226\135\189", -- ⇽
lobrk = "\226\159\166", -- ⟦
longleftarrow = "\226\159\181", -- ⟵
Longleftarrow = "\226\159\184", -- ⟸
LongLeftArrow = "\226\159\181", -- ⟵
longleftrightarrow = "\226\159\183", -- ⟷
Longleftrightarrow = "\226\159\186", -- ⟺
LongLeftRightArrow = "\226\159\183", -- ⟷
longmapsto = "\226\159\188", -- ⟼
longrightarrow = "\226\159\182", -- ⟶
Longrightarrow = "\226\159\185", -- ⟹
LongRightArrow = "\226\159\182", -- ⟶
looparrowleft = "\226\134\171", -- ↫
looparrowright = "\226\134\172", -- ↬
lopar = "\226\166\133", -- ⦅
lopf = "\240\157\149\157", -- 𝕝
Lopf = "\240\157\149\131", -- 𝕃
loplus = "\226\168\173", -- ⨭
lotimes = "\226\168\180", -- ⨴
lowast = "\226\136\151", -- ∗
lowbar = "\95", -- _
LowerLeftArrow = "\226\134\153", -- ↙
LowerRightArrow = "\226\134\152", -- ↘
loz = "\226\151\138", -- ◊
lozenge = "\226\151\138", -- ◊
lozf = "\226\167\171", -- ⧫
lpar = "\40", -- (
lparlt = "\226\166\147", -- ⦓
lrarr = "\226\135\134", -- ⇆
lrcorner = "\226\140\159", -- ⌟
lrhar = "\226\135\139", -- ⇋
lrhard = "\226\165\173", -- ⥭
lrm = "\226\128\142", -- [left-to-right mark]
lrtri = "\226\138\191", -- ⊿
lsaquo = "\226\128\185", -- ‹
lscr = "\240\157\147\129", -- 𝓁
Lscr = "\226\132\146", -- ℒ
lsh = "\226\134\176", -- ↰
Lsh = "\226\134\176", -- ↰
lsim = "\226\137\178", -- ≲
lsime = "\226\170\141", -- ⪍
lsimg = "\226\170\143", -- ⪏
lsqb = "\91", -- [
lsquo = "\226\128\152", -- ‘
lsquor = "\226\128\154", -- ‚
lstrok = "\197\130", -- ł
Lstrok = "\197\129", -- Ł
lt = "\60", -- <
Lt = "\226\137\170", -- ≪
LT = "\60", -- <
ltcc = "\226\170\166", -- ⪦
ltcir = "\226\169\185", -- ⩹
ltdot = "\226\139\150", -- ⋖
lthree = "\226\139\139", -- ⋋
ltimes = "\226\139\137", -- ⋉
ltlarr = "\226\165\182", -- ⥶
ltquest = "\226\169\187", -- ⩻
ltri = "\226\151\131", -- ◃
ltrie = "\226\138\180", -- ⊴
ltrif = "\226\151\130", -- ◂
ltrPar = "\226\166\150", -- ⦖
lurdshar = "\226\165\138", -- ⥊
luruhar = "\226\165\166", -- ⥦
lvertneqq = "\226\137\168\239\184\128", -- ≨︀
lvnE = "\226\137\168\239\184\128", -- ≨︀
macr = "\194\175", -- ¯
male = "\226\153\130", -- ♂
malt = "\226\156\160", -- ✠
maltese = "\226\156\160", -- ✠
map = "\226\134\166", -- ↦
Map = "\226\164\133", -- ⤅
mapsto = "\226\134\166", -- ↦
mapstodown = "\226\134\167", -- ↧
mapstoleft = "\226\134\164", -- ↤
mapstoup = "\226\134\165", -- ↥
marker = "\226\150\174", -- ▮
mcomma = "\226\168\169", -- ⨩
mcy = "\208\188", -- м
Mcy = "\208\156", -- М
mdash = "\226\128\148", -- —
mDDot = "\226\136\186", -- ∺
measuredangle = "\226\136\161", -- ∡
MediumSpace = "\226\129\159", -- [medium mathematical space]
Mellintrf = "\226\132\179", -- ℳ
mfr = "\240\157\148\170", -- 𝔪
Mfr = "\240\157\148\144", -- 𝔐
mho = "\226\132\167", -- ℧
micro = "\194\181", -- µ
mid = "\226\136\163", -- ∣
midast = "\42", -- *
midcir = "\226\171\176", -- ⫰
middot = "\194\183", -- ·
minus = "\226\136\146", -- −
minusb = "\226\138\159", -- ⊟
minusd = "\226\136\184", -- ∸
minusdu = "\226\168\170", -- ⨪
MinusPlus = "\226\136\147", -- ∓
mlcp = "\226\171\155", -- ⫛
mldr = "\226\128\166", -- …
mnplus = "\226\136\147", -- ∓
models = "\226\138\167", -- ⊧
mopf = "\240\157\149\158", -- 𝕞
Mopf = "\240\157\149\132", -- 𝕄
mp = "\226\136\147", -- ∓
mscr = "\240\157\147\130", -- 𝓂
Mscr = "\226\132\179", -- ℳ
mstpos = "\226\136\190", -- ∾
mu = "\206\188", -- μ
Mu = "\206\156", -- Μ
multimap = "\226\138\184", -- ⊸
mumap = "\226\138\184", -- ⊸
nabla = "\226\136\135", -- ∇
nacute = "\197\132", -- ń
Nacute = "\197\131", -- Ń
nang = "\226\136\160\226\131\146", -- ∠⃒
nap = "\226\137\137", -- ≉
napE = "\226\169\176\204\184", -- ⩰̸
napid = "\226\137\139\204\184", -- ≋̸
napos = "\197\137", -- ʼn
napprox = "\226\137\137", -- ≉
natur = "\226\153\174", -- ♮
natural = "\226\153\174", -- ♮
naturals = "\226\132\149", -- ℕ
nbsp = "\194\160", -- [no-break space]
nbump = "\226\137\142\204\184", -- ≎̸
nbumpe = "\226\137\143\204\184", -- ≏̸
ncap = "\226\169\131", -- ⩃
ncaron = "\197\136", -- ň
Ncaron = "\197\135", -- Ň
ncedil = "\197\134", -- ņ
Ncedil = "\197\133", -- Ņ
ncong = "\226\137\135", -- ≇
ncongdot = "\226\169\173\204\184", -- ⩭̸
ncup = "\226\169\130", -- ⩂
ncy = "\208\189", -- н
Ncy = "\208\157", -- Н
ndash = "\226\128\147", -- –
ne = "\226\137\160", -- ≠
nearhk = "\226\164\164", -- ⤤
nearr = "\226\134\151", -- ↗
neArr = "\226\135\151", -- ⇗
nearrow = "\226\134\151", -- ↗
nedot = "\226\137\144\204\184", -- ≐̸
NegativeMediumSpace = "\226\128\139", -- [zero width space]
NegativeThickSpace = "\226\128\139", -- [zero width space]
NegativeThinSpace = "\226\128\139", -- [zero width space]
NegativeVeryThinSpace = "\226\128\139", -- [zero width space]
nequiv = "\226\137\162", -- ≢
nesear = "\226\164\168", -- ⤨
nesim = "\226\137\130\204\184", -- ≂̸
NestedGreaterGreater = "\226\137\171", -- ≫
NestedLessLess = "\226\137\170", -- ≪
NewLine = "\n", -- [new line]
nexist = "\226\136\132", -- ∄
nexists = "\226\136\132", -- ∄
nfr = "\240\157\148\171", -- 𝔫
Nfr = "\240\157\148\145", -- 𝔑
nge = "\226\137\177", -- ≱
ngE = "\226\137\167\204\184", -- ≧̸
ngeq = "\226\137\177", -- ≱
ngeqq = "\226\137\167\204\184", -- ≧̸
ngeqslant = "\226\169\190\204\184", -- ⩾̸
nges = "\226\169\190\204\184", -- ⩾̸
nGg = "\226\139\153\204\184", -- ⋙̸
ngsim = "\226\137\181", -- ≵
ngt = "\226\137\175", -- ≯
nGt = "\226\137\171\226\131\146", -- ≫⃒
ngtr = "\226\137\175", -- ≯
nGtv = "\226\137\171\204\184", -- ≫̸
nharr = "\226\134\174", -- ↮
nhArr = "\226\135\142", -- ⇎
nhpar = "\226\171\178", -- ⫲
ni = "\226\136\139", -- ∋
nis = "\226\139\188", -- ⋼
nisd = "\226\139\186", -- ⋺
niv = "\226\136\139", -- ∋
njcy = "\209\154", -- њ
NJcy = "\208\138", -- Њ
nlarr = "\226\134\154", -- ↚
nlArr = "\226\135\141", -- ⇍
nldr = "\226\128\165", -- ‥
nle = "\226\137\176", -- ≰
nlE = "\226\137\166\204\184", -- ≦̸
nleftarrow = "\226\134\154", -- ↚
nLeftarrow = "\226\135\141", -- ⇍
nleftrightarrow = "\226\134\174", -- ↮
nLeftrightarrow = "\226\135\142", -- ⇎
nleq = "\226\137\176", -- ≰
nleqq = "\226\137\166\204\184", -- ≦̸
nleqslant = "\226\169\189\204\184", -- ⩽̸
nles = "\226\169\189\204\184", -- ⩽̸
nless = "\226\137\174", -- ≮
nLl = "\226\139\152\204\184", -- ⋘̸
nlsim = "\226\137\180", -- ≴
nlt = "\226\137\174", -- ≮
nLt = "\226\137\170\226\131\146", -- ≪⃒
nltri = "\226\139\170", -- ⋪
nltrie = "\226\139\172", -- ⋬
nLtv = "\226\137\170\204\184", -- ≪̸
nmid = "\226\136\164", -- ∤
NoBreak = "\226\129\160", -- [word joiner]
NonBreakingSpace = "\194\160", -- [no-break space]
nopf = "\240\157\149\159", -- 𝕟
Nopf = "\226\132\149", -- ℕ
["not"] = "\194\172", -- ¬
Not = "\226\171\172", -- ⫬
NotCongruent = "\226\137\162", -- ≢
NotCupCap = "\226\137\173", -- ≭
NotDoubleVerticalBar = "\226\136\166", -- ∦
NotElement = "\226\136\137", -- ∉
NotEqual = "\226\137\160", -- ≠
NotEqualTilde = "\226\137\130\204\184", -- ≂̸
NotExists = "\226\136\132", -- ∄
NotGreater = "\226\137\175", -- ≯
NotGreaterEqual = "\226\137\177", -- ≱
NotGreaterFullEqual = "\226\137\167\204\184", -- ≧̸
NotGreaterGreater = "\226\137\171\204\184", -- ≫̸
NotGreaterLess = "\226\137\185", -- ≹
NotGreaterSlantEqual = "\226\169\190\204\184", -- ⩾̸
NotGreaterTilde = "\226\137\181", -- ≵
NotHumpDownHump = "\226\137\142\204\184", -- ≎̸
NotHumpEqual = "\226\137\143\204\184", -- ≏̸
notin = "\226\136\137", -- ∉
notindot = "\226\139\181\204\184", -- ⋵̸
notinE = "\226\139\185\204\184", -- ⋹̸
notinva = "\226\136\137", -- ∉
notinvb = "\226\139\183", -- ⋷
notinvc = "\226\139\182", -- ⋶
NotLeftTriangle = "\226\139\170", -- ⋪
NotLeftTriangleBar = "\226\167\143\204\184", -- ⧏̸
NotLeftTriangleEqual = "\226\139\172", -- ⋬
NotLess = "\226\137\174", -- ≮
NotLessEqual = "\226\137\176", -- ≰
NotLessGreater = "\226\137\184", -- ≸
NotLessLess = "\226\137\170\204\184", -- ≪̸
NotLessSlantEqual = "\226\169\189\204\184", -- ⩽̸
NotLessTilde = "\226\137\180", -- ≴
NotNestedGreaterGreater = "\226\170\162\204\184", -- ⪢̸
NotNestedLessLess = "\226\170\161\204\184", -- ⪡̸
notni = "\226\136\140", -- ∌
notniva = "\226\136\140", -- ∌
notnivb = "\226\139\190", -- ⋾
notnivc = "\226\139\189", -- ⋽
NotPrecedes = "\226\138\128", -- ⊀
NotPrecedesEqual = "\226\170\175\204\184", -- ⪯̸
NotPrecedesSlantEqual = "\226\139\160", -- ⋠
NotReverseElement = "\226\136\140", -- ∌
NotRightTriangle = "\226\139\171", -- ⋫
NotRightTriangleBar = "\226\167\144\204\184", -- ⧐̸
NotRightTriangleEqual = "\226\139\173", -- ⋭
NotSquareSubset = "\226\138\143\204\184", -- ⊏̸
NotSquareSubsetEqual = "\226\139\162", -- ⋢
NotSquareSuperset = "\226\138\144\204\184", -- ⊐̸
NotSquareSupersetEqual = "\226\139\163", -- ⋣
NotSubset = "\226\138\130\226\131\146", -- ⊂⃒
NotSubsetEqual = "\226\138\136", -- ⊈
NotSucceeds = "\226\138\129", -- ⊁
NotSucceedsEqual = "\226\170\176\204\184", -- ⪰̸
NotSucceedsSlantEqual = "\226\139\161", -- ⋡
NotSucceedsTilde = "\226\137\191\204\184", -- ≿̸
NotSuperset = "\226\138\131\226\131\146", -- ⊃⃒
NotSupersetEqual = "\226\138\137", -- ⊉
NotTilde = "\226\137\129", -- ≁
NotTildeEqual = "\226\137\132", -- ≄
NotTildeFullEqual = "\226\137\135", -- ≇
NotTildeTilde = "\226\137\137", -- ≉
NotVerticalBar = "\226\136\164", -- ∤
npar = "\226\136\166", -- ∦
nparallel = "\226\136\166", -- ∦
nparsl = "\226\171\189\226\131\165", -- ⫽⃥
npart = "\226\136\130\204\184", -- ∂̸
npolint = "\226\168\148", -- ⨔
npr = "\226\138\128", -- ⊀
nprcue = "\226\139\160", -- ⋠
npre = "\226\170\175\204\184", -- ⪯̸
nprec = "\226\138\128", -- ⊀
npreceq = "\226\170\175\204\184", -- ⪯̸
nrarr = "\226\134\155", -- ↛
nrArr = "\226\135\143", -- ⇏
nrarrc = "\226\164\179\204\184", -- ⤳̸
nrarrw = "\226\134\157\204\184", -- ↝̸
nrightarrow = "\226\134\155", -- ↛
nRightarrow = "\226\135\143", -- ⇏
nrtri = "\226\139\171", -- ⋫
nrtrie = "\226\139\173", -- ⋭
nsc = "\226\138\129", -- ⊁
nsccue = "\226\139\161", -- ⋡
nsce = "\226\170\176\204\184", -- ⪰̸
nscr = "\240\157\147\131", -- 𝓃
Nscr = "\240\157\146\169", -- 𝒩
nshortmid = "\226\136\164", -- ∤
nshortparallel = "\226\136\166", -- ∦
nsim = "\226\137\129", -- ≁
nsime = "\226\137\132", -- ≄
nsimeq = "\226\137\132", -- ≄
nsmid = "\226\136\164", -- ∤
nspar = "\226\136\166", -- ∦
nsqsube = "\226\139\162", -- ⋢
nsqsupe = "\226\139\163", -- ⋣
nsub = "\226\138\132", -- ⊄
nsube = "\226\138\136", -- ⊈
nsubE = "\226\171\133\204\184", -- ⫅̸
nsubset = "\226\138\130\226\131\146", -- ⊂⃒
nsubseteq = "\226\138\136", -- ⊈
nsubseteqq = "\226\171\133\204\184", -- ⫅̸
nsucc = "\226\138\129", -- ⊁
nsucceq = "\226\170\176\204\184", -- ⪰̸
nsup = "\226\138\133", -- ⊅
nsupe = "\226\138\137", -- ⊉
nsupE = "\226\171\134\204\184", -- ⫆̸
nsupset = "\226\138\131\226\131\146", -- ⊃⃒
nsupseteq = "\226\138\137", -- ⊉
nsupseteqq = "\226\171\134\204\184", -- ⫆̸
ntgl = "\226\137\185", -- ≹
ntilde = "\195\177", -- ñ
Ntilde = "\195\145", -- Ñ
ntlg = "\226\137\184", -- ≸
ntriangleleft = "\226\139\170", -- ⋪
ntrianglelefteq = "\226\139\172", -- ⋬
ntriangleright = "\226\139\171", -- ⋫
ntrianglerighteq = "\226\139\173", -- ⋭
nu = "\206\189", -- ν
Nu = "\206\157", -- Ν
num = "\35", -- #
numero = "\226\132\150", -- №
numsp = "\226\128\135", -- [figure space]
nvap = "\226\137\141\226\131\146", -- ≍⃒
nvdash = "\226\138\172", -- ⊬
nvDash = "\226\138\173", -- ⊭
nVdash = "\226\138\174", -- ⊮
nVDash = "\226\138\175", -- ⊯
nvge = "\226\137\165\226\131\146", -- ≥⃒
nvgt = "\62\226\131\146", -- >⃒
nvHarr = "\226\164\132", -- ⤄
nvinfin = "\226\167\158", -- ⧞
nvlArr = "\226\164\130", -- ⤂
nvle = "\226\137\164\226\131\146", -- ≤⃒
nvlt = "\60\226\131\146", -- <⃒
nvltrie = "\226\138\180\226\131\146", -- ⊴⃒
nvrArr = "\226\164\131", -- ⤃
nvrtrie = "\226\138\181\226\131\146", -- ⊵⃒
nvsim = "\226\136\188\226\131\146", -- ∼⃒
nwarhk = "\226\164\163", -- ⤣
nwarr = "\226\134\150", -- ↖
nwArr = "\226\135\150", -- ⇖
nwarrow = "\226\134\150", -- ↖
nwnear = "\226\164\167", -- ⤧
oacute = "\195\179", -- ó
Oacute = "\195\147", -- Ó
oast = "\226\138\155", -- ⊛
ocir = "\226\138\154", -- ⊚
ocirc = "\195\180", -- ô
Ocirc = "\195\148", -- Ô
ocy = "\208\190", -- о
Ocy = "\208\158", -- О
odash = "\226\138\157", -- ⊝
odblac = "\197\145", -- ő
Odblac = "\197\144", -- Ő
odiv = "\226\168\184", -- ⨸
odot = "\226\138\153", -- ⊙
odsold = "\226\166\188", -- ⦼
oelig = "\197\147", -- œ
OElig = "\197\146", -- Œ
ofcir = "\226\166\191", -- ⦿
ofr = "\240\157\148\172", -- 𝔬
Ofr = "\240\157\148\146", -- 𝔒
ogon = "\203\155", -- ˛
ograve = "\195\178", -- ò
Ograve = "\195\146", -- Ò
ogt = "\226\167\129", -- ⧁
ohbar = "\226\166\181", -- ⦵
ohm = "\206\169", -- Ω
oint = "\226\136\174", -- ∮
olarr = "\226\134\186", -- ↺
olcir = "\226\166\190", -- ⦾
olcross = "\226\166\187", -- ⦻
oline = "\226\128\190", -- ‾
olt = "\226\167\128", -- ⧀
omacr = "\197\141", -- ō
Omacr = "\197\140", -- Ō
omega = "\207\137", -- ω
Omega = "\206\169", -- Ω
omicron = "\206\191", -- ο
Omicron = "\206\159", -- Ο
omid = "\226\166\182", -- ⦶
ominus = "\226\138\150", -- ⊖
oopf = "\240\157\149\160", -- 𝕠
Oopf = "\240\157\149\134", -- 𝕆
opar = "\226\166\183", -- ⦷
OpenCurlyDoubleQuote = "\226\128\156", -- “
OpenCurlyQuote = "\226\128\152", -- ‘
operp = "\226\166\185", -- ⦹
oplus = "\226\138\149", -- ⊕
["or"] = "\226\136\168", -- ∨
Or = "\226\169\148", -- ⩔
orarr = "\226\134\187", -- ↻
ord = "\226\169\157", -- ⩝
order = "\226\132\180", -- ℴ
orderof = "\226\132\180", -- ℴ
ordf = "\194\170", -- ª
ordm = "\194\186", -- º
origof = "\226\138\182", -- ⊶
oror = "\226\169\150", -- ⩖
orslope = "\226\169\151", -- ⩗
orv = "\226\169\155", -- ⩛
oS = "\226\147\136", -- Ⓢ
oscr = "\226\132\180", -- ℴ
Oscr = "\240\157\146\170", -- 𝒪
oslash = "\195\184", -- ø
Oslash = "\195\152", -- Ø
osol = "\226\138\152", -- ⊘
otilde = "\195\181", -- õ
Otilde = "\195\149", -- Õ
otimes = "\226\138\151", -- ⊗
Otimes = "\226\168\183", -- ⨷
otimesas = "\226\168\182", -- ⨶
ouml = "\195\182", -- ö
Ouml = "\195\150", -- Ö
ovbar = "\226\140\189", -- ⌽
OverBar = "\226\128\190", -- ‾
OverBrace = "\226\143\158", -- ⏞
OverBracket = "\226\142\180", -- ⎴
OverParenthesis = "\226\143\156", -- ⏜
par = "\226\136\165", -- ∥
para = "\194\182", -- ¶
parallel = "\226\136\165", -- ∥
parsim = "\226\171\179", -- ⫳
parsl = "\226\171\189", -- ⫽
part = "\226\136\130", -- ∂
PartialD = "\226\136\130", -- ∂
pcy = "\208\191", -- п
Pcy = "\208\159", -- П
percnt = "\37", -- %
period = "\46", -- .
permil = "\226\128\176", -- ‰
perp = "\226\138\165", -- ⊥
pertenk = "\226\128\177", -- ‱
pfr = "\240\157\148\173", -- 𝔭
Pfr = "\240\157\148\147", -- 𝔓
phi = "\207\134", -- φ
Phi = "\206\166", -- Φ
phiv = "\207\149", -- ϕ
phmmat = "\226\132\179", -- ℳ
phone = "\226\152\142", -- ☎
pi = "\207\128", -- π
Pi = "\206\160", -- Π
pitchfork = "\226\139\148", -- ⋔
piv = "\207\150", -- ϖ
planck = "\226\132\143", -- ℏ
planckh = "\226\132\142", -- ℎ
plankv = "\226\132\143", -- ℏ
plus = "\43", -- +
plusacir = "\226\168\163", -- ⨣
plusb = "\226\138\158", -- ⊞
pluscir = "\226\168\162", -- ⨢
plusdo = "\226\136\148", -- ∔
plusdu = "\226\168\165", -- ⨥
pluse = "\226\169\178", -- ⩲
PlusMinus = "\194\177", -- ±
plusmn = "\194\177", -- ±
plussim = "\226\168\166", -- ⨦
plustwo = "\226\168\167", -- ⨧
pm = "\194\177", -- ±
Poincareplane = "\226\132\140", -- ℌ
pointint = "\226\168\149", -- ⨕
popf = "\240\157\149\161", -- 𝕡
Popf = "\226\132\153", -- ℙ
pound = "\194\163", -- £
pr = "\226\137\186", -- ≺
Pr = "\226\170\187", -- ⪻
prap = "\226\170\183", -- ⪷
prcue = "\226\137\188", -- ≼
pre = "\226\170\175", -- ⪯
prE = "\226\170\179", -- ⪳
prec = "\226\137\186", -- ≺
precapprox = "\226\170\183", -- ⪷
preccurlyeq = "\226\137\188", -- ≼
Precedes = "\226\137\186", -- ≺
PrecedesEqual = "\226\170\175", -- ⪯
PrecedesSlantEqual = "\226\137\188", -- ≼
PrecedesTilde = "\226\137\190", -- ≾
preceq = "\226\170\175", -- ⪯
precnapprox = "\226\170\185", -- ⪹
precneqq = "\226\170\181", -- ⪵
precnsim = "\226\139\168", -- ⋨
precsim = "\226\137\190", -- ≾
prime = "\226\128\178", -- ′
Prime = "\226\128\179", -- ″
primes = "\226\132\153", -- ℙ
prnap = "\226\170\185", -- ⪹
prnE = "\226\170\181", -- ⪵
prnsim = "\226\139\168", -- ⋨
prod = "\226\136\143", -- ∏
Product = "\226\136\143", -- ∏
profalar = "\226\140\174", -- ⌮
profline = "\226\140\146", -- ⌒
profsurf = "\226\140\147", -- ⌓
prop = "\226\136\157", -- ∝
Proportion = "\226\136\183", -- ∷
Proportional = "\226\136\157", -- ∝
propto = "\226\136\157", -- ∝
prsim = "\226\137\190", -- ≾
prurel = "\226\138\176", -- ⊰
pscr = "\240\157\147\133", -- 𝓅
Pscr = "\240\157\146\171", -- 𝒫
psi = "\207\136", -- ψ
Psi = "\206\168", -- Ψ
puncsp = "\226\128\136", -- [punctuation space]
qfr = "\240\157\148\174", -- 𝔮
Qfr = "\240\157\148\148", -- 𝔔
qint = "\226\168\140", -- ⨌
qopf = "\240\157\149\162", -- 𝕢
Qopf = "\226\132\154", -- ℚ
qprime = "\226\129\151", -- ⁗
qscr = "\240\157\147\134", -- 𝓆
Qscr = "\240\157\146\172", -- 𝒬
quaternions = "\226\132\141", -- ℍ
quatint = "\226\168\150", -- ⨖
quest = "\63", -- ?
questeq = "\226\137\159", -- ≟
quot = "\34", -- "
QUOT = "\34", -- "
rAarr = "\226\135\155", -- ⇛
race = "\226\136\189\204\177", -- ∽̱
racute = "\197\149", -- ŕ
Racute = "\197\148", -- Ŕ
radic = "\226\136\154", -- √
raemptyv = "\226\166\179", -- ⦳
rang = "\226\159\169", -- ⟩
Rang = "\226\159\171", -- ⟫
rangd = "\226\166\146", -- ⦒
range = "\226\166\165", -- ⦥
rangle = "\226\159\169", -- ⟩
raquo = "\194\187", -- »
rarr = "\226\134\146", -- →
rArr = "\226\135\146", -- ⇒
Rarr = "\226\134\160", -- ↠
rarrap = "\226\165\181", -- ⥵
rarrb = "\226\135\165", -- ⇥
rarrbfs = "\226\164\160", -- ⤠
rarrc = "\226\164\179", -- ⤳
rarrfs = "\226\164\158", -- ⤞
rarrhk = "\226\134\170", -- ↪
rarrlp = "\226\134\172", -- ↬
rarrpl = "\226\165\133", -- ⥅
rarrsim = "\226\165\180", -- ⥴
rarrtl = "\226\134\163", -- ↣
Rarrtl = "\226\164\150", -- ⤖
rarrw = "\226\134\157", -- ↝
ratail = "\226\164\154", -- ⤚
rAtail = "\226\164\156", -- ⤜
ratio = "\226\136\182", -- ∶
rationals = "\226\132\154", -- ℚ
rbarr = "\226\164\141", -- ⤍
rBarr = "\226\164\143", -- ⤏
RBarr = "\226\164\144", -- ⤐
rbbrk = "\226\157\179", -- ❳
rbrace = "\125", -- }
rbrack = "\93", -- ]
rbrke = "\226\166\140", -- ⦌
rbrksld = "\226\166\142", -- ⦎
rbrkslu = "\226\166\144", -- ⦐
rcaron = "\197\153", -- ř
Rcaron = "\197\152", -- Ř
rcedil = "\197\151", -- ŗ
Rcedil = "\197\150", -- Ŗ
rceil = "\226\140\137", -- ⌉
rcub = "\125", -- }
rcy = "\209\128", -- р
Rcy = "\208\160", -- Р
rdca = "\226\164\183", -- ⤷
rdldhar = "\226\165\169", -- ⥩
rdquo = "\226\128\157", -- ”
rdquor = "\226\128\157", -- ”
rdsh = "\226\134\179", -- ↳
Re = "\226\132\156", -- ℜ
real = "\226\132\156", -- ℜ
realine = "\226\132\155", -- ℛ
realpart = "\226\132\156", -- ℜ
reals = "\226\132\157", -- ℝ
rect = "\226\150\173", -- ▭
reg = "\194\174", -- ®
REG = "\194\174", -- ®
ReverseElement = "\226\136\139", -- ∋
ReverseEquilibrium = "\226\135\139", -- ⇋
ReverseUpEquilibrium = "\226\165\175", -- ⥯
rfisht = "\226\165\189", -- ⥽
rfloor = "\226\140\139", -- ⌋
rfr = "\240\157\148\175", -- 𝔯
Rfr = "\226\132\156", -- ℜ
rHar = "\226\165\164", -- ⥤
rhard = "\226\135\129", -- ⇁
rharu = "\226\135\128", -- ⇀
rharul = "\226\165\172", -- ⥬
rho = "\207\129", -- ρ
Rho = "\206\161", -- Ρ
rhov = "\207\177", -- ϱ
RightAngleBracket = "\226\159\169", -- ⟩
rightarrow = "\226\134\146", -- →
Rightarrow = "\226\135\146", -- ⇒
RightArrow = "\226\134\146", -- →
RightArrowBar = "\226\135\165", -- ⇥
RightArrowLeftArrow = "\226\135\132", -- ⇄
rightarrowtail = "\226\134\163", -- ↣
RightCeiling = "\226\140\137", -- ⌉
RightDoubleBracket = "\226\159\167", -- ⟧
RightDownTeeVector = "\226\165\157", -- ⥝
RightDownVector = "\226\135\130", -- ⇂
RightDownVectorBar = "\226\165\149", -- ⥕
RightFloor = "\226\140\139", -- ⌋
rightharpoondown = "\226\135\129", -- ⇁
rightharpoonup = "\226\135\128", -- ⇀
rightleftarrows = "\226\135\132", -- ⇄
rightleftharpoons = "\226\135\140", -- ⇌
rightrightarrows = "\226\135\137", -- ⇉
rightsquigarrow = "\226\134\157", -- ↝
RightTee = "\226\138\162", -- ⊢
RightTeeArrow = "\226\134\166", -- ↦
RightTeeVector = "\226\165\155", -- ⥛
rightthreetimes = "\226\139\140", -- ⋌
RightTriangle = "\226\138\179", -- ⊳
RightTriangleBar = "\226\167\144", -- ⧐
RightTriangleEqual = "\226\138\181", -- ⊵
RightUpDownVector = "\226\165\143", -- ⥏
RightUpTeeVector = "\226\165\156", -- ⥜
RightUpVector = "\226\134\190", -- ↾
RightUpVectorBar = "\226\165\148", -- ⥔
RightVector = "\226\135\128", -- ⇀
RightVectorBar = "\226\165\147", -- ⥓
ring = "\203\154", -- ˚
risingdotseq = "\226\137\147", -- ≓
rlarr = "\226\135\132", -- ⇄
rlhar = "\226\135\140", -- ⇌
rlm = "\226\128\143", -- [right-to-left mark]
rmoust = "\226\142\177", -- ⎱
rmoustache = "\226\142\177", -- ⎱
rnmid = "\226\171\174", -- ⫮
roang = "\226\159\173", -- ⟭
roarr = "\226\135\190", -- ⇾
robrk = "\226\159\167", -- ⟧
ropar = "\226\166\134", -- ⦆
ropf = "\240\157\149\163", -- 𝕣
Ropf = "\226\132\157", -- ℝ
roplus = "\226\168\174", -- ⨮
rotimes = "\226\168\181", -- ⨵
RoundImplies = "\226\165\176", -- ⥰
rpar = "\41", -- )
rpargt = "\226\166\148", -- ⦔
rppolint = "\226\168\146", -- ⨒
rrarr = "\226\135\137", -- ⇉
Rrightarrow = "\226\135\155", -- ⇛
rsaquo = "\226\128\186", -- ›
rscr = "\240\157\147\135", -- 𝓇
Rscr = "\226\132\155", -- ℛ
rsh = "\226\134\177", -- ↱
Rsh = "\226\134\177", -- ↱
rsqb = "\93", -- ]
rsquo = "\226\128\153", -- ’
rsquor = "\226\128\153", -- ’
rthree = "\226\139\140", -- ⋌
rtimes = "\226\139\138", -- ⋊
rtri = "\226\150\185", -- ▹
rtrie = "\226\138\181", -- ⊵
rtrif = "\226\150\184", -- ▸
rtriltri = "\226\167\142", -- ⧎
RuleDelayed = "\226\167\180", -- ⧴
ruluhar = "\226\165\168", -- ⥨
rx = "\226\132\158", -- ℞
sacute = "\197\155", -- ś
Sacute = "\197\154", -- Ś
sbquo = "\226\128\154", -- ‚
sc = "\226\137\187", -- ≻
Sc = "\226\170\188", -- ⪼
scap = "\226\170\184", -- ⪸
scaron = "\197\161", -- š
Scaron = "\197\160", -- Š
sccue = "\226\137\189", -- ≽
sce = "\226\170\176", -- ⪰
scE = "\226\170\180", -- ⪴
scedil = "\197\159", -- ş
Scedil = "\197\158", -- Ş
scirc = "\197\157", -- ŝ
Scirc = "\197\156", -- Ŝ
scnap = "\226\170\186", -- ⪺
scnE = "\226\170\182", -- ⪶
scnsim = "\226\139\169", -- ⋩
scpolint = "\226\168\147", -- ⨓
scsim = "\226\137\191", -- ≿
scy = "\209\129", -- с
Scy = "\208\161", -- С
sdot = "\226\139\133", -- ⋅
sdotb = "\226\138\161", -- ⊡
sdote = "\226\169\166", -- ⩦
searhk = "\226\164\165", -- ⤥
searr = "\226\134\152", -- ↘
seArr = "\226\135\152", -- ⇘
searrow = "\226\134\152", -- ↘
sect = "\194\167", -- §
semi = "\59", -- ;
seswar = "\226\164\169", -- ⤩
setminus = "\226\136\150", -- ∖
setmn = "\226\136\150", -- ∖
sext = "\226\156\182", -- ✶
sfr = "\240\157\148\176", -- 𝔰
Sfr = "\240\157\148\150", -- 𝔖
sfrown = "\226\140\162", -- ⌢
sharp = "\226\153\175", -- ♯
shchcy = "\209\137", -- щ
SHCHcy = "\208\169", -- Щ
shcy = "\209\136", -- ш
SHcy = "\208\168", -- Ш
ShortDownArrow = "\226\134\147", -- ↓
ShortLeftArrow = "\226\134\144", -- ←
shortmid = "\226\136\163", -- ∣
shortparallel = "\226\136\165", -- ∥
ShortRightArrow = "\226\134\146", -- →
ShortUpArrow = "\226\134\145", -- ↑
shy = "\194\173", -- [soft hyphen]
sigma = "\207\131", -- σ
Sigma = "\206\163", -- Σ
sigmaf = "\207\130", -- ς
sigmav = "\207\130", -- ς
sim = "\226\136\188", -- ∼
simdot = "\226\169\170", -- ⩪
sime = "\226\137\131", -- ≃
simeq = "\226\137\131", -- ≃
simg = "\226\170\158", -- ⪞
simgE = "\226\170\160", -- ⪠
siml = "\226\170\157", -- ⪝
simlE = "\226\170\159", -- ⪟
simne = "\226\137\134", -- ≆
simplus = "\226\168\164", -- ⨤
simrarr = "\226\165\178", -- ⥲
slarr = "\226\134\144", -- ←
SmallCircle = "\226\136\152", -- ∘
smallsetminus = "\226\136\150", -- ∖
smashp = "\226\168\179", -- ⨳
smeparsl = "\226\167\164", -- ⧤
smid = "\226\136\163", -- ∣
smile = "\226\140\163", -- ⌣
smt = "\226\170\170", -- ⪪
smte = "\226\170\172", -- ⪬
smtes = "\226\170\172\239\184\128", -- ⪬︀
softcy = "\209\140", -- ь
SOFTcy = "\208\172", -- Ь
sol = "\47", -- /
solb = "\226\167\132", -- ⧄
solbar = "\226\140\191", -- ⌿
sopf = "\240\157\149\164", -- 𝕤
Sopf = "\240\157\149\138", -- 𝕊
spades = "\226\153\160", -- ♠
spadesuit = "\226\153\160", -- ♠
spar = "\226\136\165", -- ∥
sqcap = "\226\138\147", -- ⊓
sqcaps = "\226\138\147\239\184\128", -- ⊓︀
sqcup = "\226\138\148", -- ⊔
sqcups = "\226\138\148\239\184\128", -- ⊔︀
Sqrt = "\226\136\154", -- √
sqsub = "\226\138\143", -- ⊏
sqsube = "\226\138\145", -- ⊑
sqsubset = "\226\138\143", -- ⊏
sqsubseteq = "\226\138\145", -- ⊑
sqsup = "\226\138\144", -- ⊐
sqsupe = "\226\138\146", -- ⊒
sqsupset = "\226\138\144", -- ⊐
sqsupseteq = "\226\138\146", -- ⊒
squ = "\226\150\161", -- □
square = "\226\150\161", -- □
Square = "\226\150\161", -- □
SquareIntersection = "\226\138\147", -- ⊓
SquareSubset = "\226\138\143", -- ⊏
SquareSubsetEqual = "\226\138\145", -- ⊑
SquareSuperset = "\226\138\144", -- ⊐
SquareSupersetEqual = "\226\138\146", -- ⊒
SquareUnion = "\226\138\148", -- ⊔
squarf = "\226\150\170", -- ▪
squf = "\226\150\170", -- ▪
srarr = "\226\134\146", -- →
sscr = "\240\157\147\136", -- 𝓈
Sscr = "\240\157\146\174", -- 𝒮
ssetmn = "\226\136\150", -- ∖
ssmile = "\226\140\163", -- ⌣
sstarf = "\226\139\134", -- ⋆
star = "\226\152\134", -- ☆
Star = "\226\139\134", -- ⋆
starf = "\226\152\133", -- ★
straightepsilon = "\207\181", -- ϵ
straightphi = "\207\149", -- ϕ
strns = "\194\175", -- ¯
sub = "\226\138\130", -- ⊂
Sub = "\226\139\144", -- ⋐
subdot = "\226\170\189", -- ⪽
sube = "\226\138\134", -- ⊆
subE = "\226\171\133", -- ⫅
subedot = "\226\171\131", -- ⫃
submult = "\226\171\129", -- ⫁
subne = "\226\138\138", -- ⊊
subnE = "\226\171\139", -- ⫋
subplus = "\226\170\191", -- ⪿
subrarr = "\226\165\185", -- ⥹
subset = "\226\138\130", -- ⊂
Subset = "\226\139\144", -- ⋐
subseteq = "\226\138\134", -- ⊆
subseteqq = "\226\171\133", -- ⫅
SubsetEqual = "\226\138\134", -- ⊆
subsetneq = "\226\138\138", -- ⊊
subsetneqq = "\226\171\139", -- ⫋
subsim = "\226\171\135", -- ⫇
subsub = "\226\171\149", -- ⫕
subsup = "\226\171\147", -- ⫓
succ = "\226\137\187", -- ≻
succapprox = "\226\170\184", -- ⪸
succcurlyeq = "\226\137\189", -- ≽
Succeeds = "\226\137\187", -- ≻
SucceedsEqual = "\226\170\176", -- ⪰
SucceedsSlantEqual = "\226\137\189", -- ≽
SucceedsTilde = "\226\137\191", -- ≿
succeq = "\226\170\176", -- ⪰
succnapprox = "\226\170\186", -- ⪺
succneqq = "\226\170\182", -- ⪶
succnsim = "\226\139\169", -- ⋩
succsim = "\226\137\191", -- ≿
SuchThat = "\226\136\139", -- ∋
sum = "\226\136\145", -- ∑
Sum = "\226\136\145", -- ∑
sung = "\226\153\170", -- ♪
sup = "\226\138\131", -- ⊃
Sup = "\226\139\145", -- ⋑
sup1 = "\194\185", -- ¹
sup2 = "\194\178", -- ²
sup3 = "\194\179", -- ³
supdot = "\226\170\190", -- ⪾
supdsub = "\226\171\152", -- ⫘
supe = "\226\138\135", -- ⊇
supE = "\226\171\134", -- ⫆
supedot = "\226\171\132", -- ⫄
Superset = "\226\138\131", -- ⊃
SupersetEqual = "\226\138\135", -- ⊇
suphsol = "\226\159\137", -- ⟉
suphsub = "\226\171\151", -- ⫗
suplarr = "\226\165\187", -- ⥻
supmult = "\226\171\130", -- ⫂
supne = "\226\138\139", -- ⊋
supnE = "\226\171\140", -- ⫌
supplus = "\226\171\128", -- ⫀
supset = "\226\138\131", -- ⊃
Supset = "\226\139\145", -- ⋑
supseteq = "\226\138\135", -- ⊇
supseteqq = "\226\171\134", -- ⫆
supsetneq = "\226\138\139", -- ⊋
supsetneqq = "\226\171\140", -- ⫌
supsim = "\226\171\136", -- ⫈
supsub = "\226\171\148", -- ⫔
supsup = "\226\171\150", -- ⫖
swarhk = "\226\164\166", -- ⤦
swarr = "\226\134\153", -- ↙
swArr = "\226\135\153", -- ⇙
swarrow = "\226\134\153", -- ↙
swnwar = "\226\164\170", -- ⤪
szlig = "\195\159", -- ß
Tab = "\t", -- [tab]
target = "\226\140\150", -- ⌖
tau = "\207\132", -- τ
Tau = "\206\164", -- Τ
tbrk = "\226\142\180", -- ⎴
tcaron = "\197\165", -- ť
Tcaron = "\197\164", -- Ť
tcedil = "\197\163", -- ţ
Tcedil = "\197\162", -- Ţ
tcy = "\209\130", -- т
Tcy = "\208\162", -- Т
tdot = "\226\131\155", -- ⃛
telrec = "\226\140\149", -- ⌕
tfr = "\240\157\148\177", -- 𝔱
Tfr = "\240\157\148\151", -- 𝔗
there4 = "\226\136\180", -- ∴
therefore = "\226\136\180", -- ∴
Therefore = "\226\136\180", -- ∴
theta = "\206\184", -- θ
Theta = "\206\152", -- Θ
thetasym = "\207\145", -- ϑ
thetav = "\207\145", -- ϑ
thickapprox = "\226\137\136", -- ≈
thicksim = "\226\136\188", -- ∼
ThickSpace = "\226\129\159\226\128\138", -- [medium mathematical space] + [hair space]
thinsp = "\226\128\137", -- [thin space]
ThinSpace = "\226\128\137", -- [thin space]
thkap = "\226\137\136", -- ≈
thksim = "\226\136\188", -- ∼
thorn = "\195\190", -- þ
THORN = "\195\158", -- Þ
tilde = "\203\156", -- ˜
Tilde = "\226\136\188", -- ∼
TildeEqual = "\226\137\131", -- ≃
TildeFullEqual = "\226\137\133", -- ≅
TildeTilde = "\226\137\136", -- ≈
times = "\195\151", -- ×
timesb = "\226\138\160", -- ⊠
timesbar = "\226\168\177", -- ⨱
timesd = "\226\168\176", -- ⨰
tint = "\226\136\173", -- ∭
toea = "\226\164\168", -- ⤨
top = "\226\138\164", -- ⊤
topbot = "\226\140\182", -- ⌶
topcir = "\226\171\177", -- ⫱
topf = "\240\157\149\165", -- 𝕥
Topf = "\240\157\149\139", -- 𝕋
topfork = "\226\171\154", -- ⫚
tosa = "\226\164\169", -- ⤩
tprime = "\226\128\180", -- ‴
trade = "\226\132\162", -- ™
TRADE = "\226\132\162", -- ™
triangle = "\226\150\181", -- ▵
triangledown = "\226\150\191", -- ▿
triangleleft = "\226\151\131", -- ◃
trianglelefteq = "\226\138\180", -- ⊴
triangleq = "\226\137\156", -- ≜
triangleright = "\226\150\185", -- ▹
trianglerighteq = "\226\138\181", -- ⊵
tridot = "\226\151\172", -- ◬
trie = "\226\137\156", -- ≜
triminus = "\226\168\186", -- ⨺
TripleDot = "\226\131\155", -- ⃛
triplus = "\226\168\185", -- ⨹
trisb = "\226\167\141", -- ⧍
tritime = "\226\168\187", -- ⨻
trpezium = "\226\143\162", -- ⏢
tscr = "\240\157\147\137", -- 𝓉
Tscr = "\240\157\146\175", -- 𝒯
tscy = "\209\134", -- ц
TScy = "\208\166", -- Ц
tshcy = "\209\155", -- ћ
TSHcy = "\208\139", -- Ћ
tstrok = "\197\167", -- ŧ
Tstrok = "\197\166", -- Ŧ
twixt = "\226\137\172", -- ≬
twoheadleftarrow = "\226\134\158", -- ↞
twoheadrightarrow = "\226\134\160", -- ↠
uacute = "\195\186", -- ú
Uacute = "\195\154", -- Ú
uarr = "\226\134\145", -- ↑
uArr = "\226\135\145", -- ⇑
Uarr = "\226\134\159", -- ↟
Uarrocir = "\226\165\137", -- ⥉
ubrcy = "\209\158", -- ў
Ubrcy = "\208\142", -- Ў
ubreve = "\197\173", -- ŭ
Ubreve = "\197\172", -- Ŭ
ucirc = "\195\187", -- û
Ucirc = "\195\155", -- Û
ucy = "\209\131", -- у
Ucy = "\208\163", -- У
udarr = "\226\135\133", -- ⇅
udblac = "\197\177", -- ű
Udblac = "\197\176", -- Ű
udhar = "\226\165\174", -- ⥮
ufisht = "\226\165\190", -- ⥾
ufr = "\240\157\148\178", -- 𝔲
Ufr = "\240\157\148\152", -- 𝔘
ugrave = "\195\185", -- ù
Ugrave = "\195\153", -- Ù
uHar = "\226\165\163", -- ⥣
uharl = "\226\134\191", -- ↿
uharr = "\226\134\190", -- ↾
uhblk = "\226\150\128", -- ▀
ulcorn = "\226\140\156", -- ⌜
ulcorner = "\226\140\156", -- ⌜
ulcrop = "\226\140\143", -- ⌏
ultri = "\226\151\184", -- ◸
umacr = "\197\171", -- ū
Umacr = "\197\170", -- Ū
uml = "\194\168", -- ¨
UnderBar = "\95", -- _
UnderBrace = "\226\143\159", -- ⏟
UnderBracket = "\226\142\181", -- ⎵
UnderParenthesis = "\226\143\157", -- ⏝
Union = "\226\139\131", -- ⋃
UnionPlus = "\226\138\142", -- ⊎
uogon = "\197\179", -- ų
Uogon = "\197\178", -- Ų
uopf = "\240\157\149\166", -- 𝕦
Uopf = "\240\157\149\140", -- 𝕌
uparrow = "\226\134\145", -- ↑
Uparrow = "\226\135\145", -- ⇑
UpArrow = "\226\134\145", -- ↑
UpArrowBar = "\226\164\146", -- ⤒
UpArrowDownArrow = "\226\135\133", -- ⇅
updownarrow = "\226\134\149", -- ↕
Updownarrow = "\226\135\149", -- ⇕
UpDownArrow = "\226\134\149", -- ↕
UpEquilibrium = "\226\165\174", -- ⥮
upharpoonleft = "\226\134\191", -- ↿
upharpoonright = "\226\134\190", -- ↾
uplus = "\226\138\142", -- ⊎
UpperLeftArrow = "\226\134\150", -- ↖
UpperRightArrow = "\226\134\151", -- ↗
upsi = "\207\133", -- υ
Upsi = "\207\146", -- ϒ
upsih = "\207\146", -- ϒ
upsilon = "\207\133", -- υ
Upsilon = "\206\165", -- Υ
UpTee = "\226\138\165", -- ⊥
UpTeeArrow = "\226\134\165", -- ↥
upuparrows = "\226\135\136", -- ⇈
urcorn = "\226\140\157", -- ⌝
urcorner = "\226\140\157", -- ⌝
urcrop = "\226\140\142", -- ⌎
uring = "\197\175", -- ů
Uring = "\197\174", -- Ů
urtri = "\226\151\185", -- ◹
uscr = "\240\157\147\138", -- 𝓊
Uscr = "\240\157\146\176", -- 𝒰
utdot = "\226\139\176", -- ⋰
utilde = "\197\169", -- ũ
Utilde = "\197\168", -- Ũ
utri = "\226\150\181", -- ▵
utrif = "\226\150\180", -- ▴
uuarr = "\226\135\136", -- ⇈
uuml = "\195\188", -- ü
Uuml = "\195\156", -- Ü
uwangle = "\226\166\167", -- ⦧
vangrt = "\226\166\156", -- ⦜
varepsilon = "\207\181", -- ϵ
varkappa = "\207\176", -- ϰ
varnothing = "\226\136\133", -- ∅
varphi = "\207\149", -- ϕ
varpi = "\207\150", -- ϖ
varpropto = "\226\136\157", -- ∝
varr = "\226\134\149", -- ↕
vArr = "\226\135\149", -- ⇕
varrho = "\207\177", -- ϱ
varsigma = "\207\130", -- ς
varsubsetneq = "\226\138\138\239\184\128", -- ⊊︀
varsubsetneqq = "\226\171\139\239\184\128", -- ⫋︀
varsupsetneq = "\226\138\139\239\184\128", -- ⊋︀
varsupsetneqq = "\226\171\140\239\184\128", -- ⫌︀
vartheta = "\207\145", -- ϑ
vartriangleleft = "\226\138\178", -- ⊲
vartriangleright = "\226\138\179", -- ⊳
vBar = "\226\171\168", -- ⫨
Vbar = "\226\171\171", -- ⫫
vBarv = "\226\171\169", -- ⫩
vcy = "\208\178", -- в
Vcy = "\208\146", -- В
vdash = "\226\138\162", -- ⊢
vDash = "\226\138\168", -- ⊨
Vdash = "\226\138\169", -- ⊩
VDash = "\226\138\171", -- ⊫
Vdashl = "\226\171\166", -- ⫦
vee = "\226\136\168", -- ∨
Vee = "\226\139\129", -- ⋁
veebar = "\226\138\187", -- ⊻
veeeq = "\226\137\154", -- ≚
vellip = "\226\139\174", -- ⋮
verbar = "\124", -- |
Verbar = "\226\128\150", -- ‖
vert = "\124", -- |
Vert = "\226\128\150", -- ‖
VerticalBar = "\226\136\163", -- ∣
VerticalLine = "\124", -- |
VerticalSeparator = "\226\157\152", -- ❘
VerticalTilde = "\226\137\128", -- ≀
VeryThinSpace = "\226\128\138", -- [hair space]
vfr = "\240\157\148\179", -- 𝔳
Vfr = "\240\157\148\153", -- 𝔙
vltri = "\226\138\178", -- ⊲
vnsub = "\226\138\130\226\131\146", -- ⊂⃒
vnsup = "\226\138\131\226\131\146", -- ⊃⃒
vopf = "\240\157\149\167", -- 𝕧
Vopf = "\240\157\149\141", -- 𝕍
vprop = "\226\136\157", -- ∝
vrtri = "\226\138\179", -- ⊳
vscr = "\240\157\147\139", -- 𝓋
Vscr = "\240\157\146\177", -- 𝒱
vsubne = "\226\138\138\239\184\128", -- ⊊︀
vsubnE = "\226\171\139\239\184\128", -- ⫋︀
vsupne = "\226\138\139\239\184\128", -- ⊋︀
vsupnE = "\226\171\140\239\184\128", -- ⫌︀
Vvdash = "\226\138\170", -- ⊪
vzigzag = "\226\166\154", -- ⦚
wcirc = "\197\181", -- ŵ
Wcirc = "\197\180", -- Ŵ
wedbar = "\226\169\159", -- ⩟
wedge = "\226\136\167", -- ∧
Wedge = "\226\139\128", -- ⋀
wedgeq = "\226\137\153", -- ≙
weierp = "\226\132\152", -- ℘
wfr = "\240\157\148\180", -- 𝔴
Wfr = "\240\157\148\154", -- 𝔚
wopf = "\240\157\149\168", -- 𝕨
Wopf = "\240\157\149\142", -- 𝕎
wp = "\226\132\152", -- ℘
wr = "\226\137\128", -- ≀
wreath = "\226\137\128", -- ≀
wscr = "\240\157\147\140", -- 𝓌
Wscr = "\240\157\146\178", -- 𝒲
xcap = "\226\139\130", -- ⋂
xcirc = "\226\151\175", -- ◯
xcup = "\226\139\131", -- ⋃
xdtri = "\226\150\189", -- ▽
xfr = "\240\157\148\181", -- 𝔵
Xfr = "\240\157\148\155", -- 𝔛
xharr = "\226\159\183", -- ⟷
xhArr = "\226\159\186", -- ⟺
xi = "\206\190", -- ξ
Xi = "\206\158", -- Ξ
xlarr = "\226\159\181", -- ⟵
xlArr = "\226\159\184", -- ⟸
xmap = "\226\159\188", -- ⟼
xnis = "\226\139\187", -- ⋻
xodot = "\226\168\128", -- ⨀
xopf = "\240\157\149\169", -- 𝕩
Xopf = "\240\157\149\143", -- 𝕏
xoplus = "\226\168\129", -- ⨁
xotime = "\226\168\130", -- ⨂
xrarr = "\226\159\182", -- ⟶
xrArr = "\226\159\185", -- ⟹
xscr = "\240\157\147\141", -- 𝓍
Xscr = "\240\157\146\179", -- 𝒳
xsqcup = "\226\168\134", -- ⨆
xuplus = "\226\168\132", -- ⨄
xutri = "\226\150\179", -- △
xvee = "\226\139\129", -- ⋁
xwedge = "\226\139\128", -- ⋀
yacute = "\195\189", -- ý
Yacute = "\195\157", -- Ý
yacy = "\209\143", -- я
YAcy = "\208\175", -- Я
ycirc = "\197\183", -- ŷ
Ycirc = "\197\182", -- Ŷ
ycy = "\209\139", -- ы
Ycy = "\208\171", -- Ы
yen = "\194\165", -- ¥
yfr = "\240\157\148\182", -- 𝔶
Yfr = "\240\157\148\156", -- 𝔜
yicy = "\209\151", -- ї
YIcy = "\208\135", -- Ї
yopf = "\240\157\149\170", -- 𝕪
Yopf = "\240\157\149\144", -- 𝕐
yscr = "\240\157\147\142", -- 𝓎
Yscr = "\240\157\146\180", -- 𝒴
yucy = "\209\142", -- ю
YUcy = "\208\174", -- Ю
yuml = "\195\191", -- ÿ
Yuml = "\197\184", -- Ÿ
zacute = "\197\186", -- ź
Zacute = "\197\185", -- Ź
zcaron = "\197\190", -- ž
Zcaron = "\197\189", -- Ž
zcy = "\208\183", -- з
Zcy = "\208\151", -- З
zdot = "\197\188", -- ż
Zdot = "\197\187", -- Ż
zeetrf = "\226\132\168", -- ℨ
ZeroWidthSpace = "\226\128\139", -- [zero width space]
zeta = "\206\182", -- ζ
Zeta = "\206\150", -- Ζ
zfr = "\240\157\148\183", -- 𝔷
Zfr = "\226\132\168", -- ℨ
zhcy = "\208\182", -- ж
ZHcy = "\208\150", -- Ж
zigrarr = "\226\135\157", -- ⇝
zopf = "\240\157\149\171", -- 𝕫
Zopf = "\226\132\164", -- ℤ
zscr = "\240\157\147\143", -- 𝓏
Zscr = "\240\157\146\181", -- 𝒵
zwj = "\226\128\141", -- [zero width joiner]
zwnj = "\226\128\140", -- [zero width non-joiner]
-- Nonstandard, but accepted by MediaWiki.
["רלמ"] = "\226\128\143", -- [right-to-left mark]
["رلم"] = "\226\128\143", -- [right-to-left mark]
}
8o4sqdodbkfwk9xmp2f1xlrb7zei3p7
Modul:parser
828
41868
218845
187742
2025-06-20T00:28:03Z
Sponge2490
8927
Mengemaskini berdasarkan Module:parser pada 14 Mei 2025 (84802573)
218845
Scribunto
text/plain
local export = {}
local scribunto_metamethods_module = "Module:Scribunto/metamethods"
local table_deep_copy_module = "Module:table/deepCopy"
local table_get_nested_module = "Module:table/getNested"
local table_set_nested_module = "Module:table/setNested"
local concat = table.concat
local find = string.find
local getmetatable = getmetatable
local insert = table.insert
local next = next
local rawget = rawget
local rawset = rawset
local remove = table.remove
local require = require
local select = select
local setmetatable = setmetatable
local sub = string.sub
local type = type
local unpack = unpack or table.unpack -- Lua 5.2 compatibility
local node_classes = {}
local function deep_copy(...)
deep_copy = require(table_deep_copy_module)
return deep_copy(...)
end
local function get_nested(...)
get_nested = require(table_get_nested_module)
return get_nested(...)
end
local function set_nested(...)
set_nested = require(table_set_nested_module)
return set_nested(...)
end
--[==[
Loaders for objects, which load data (or some other object) into some variable, which can then be accessed as "foo or get_foo()", where the function get_foo sets the object to "foo" and then returns it. This ensures they are only loaded when needed, and avoids the need to check for the existence of the object each time, since once "foo" has been set, "get_foo" will not be called again.]==]
local metamethods
local function get_metamethods()
-- Use require, since lookup times are much slower with mw.loadData.
metamethods, get_metamethods = require(scribunto_metamethods_module), nil
return metamethods
end
------------------------------------------------------------------------------------
--
-- Helper functions
--
------------------------------------------------------------------------------------
local function inherit_metamethods(child, parent)
if parent then
for method, value in next, parent do
if child[method] == nil and (metamethods or get_metamethods())[method] ~= nil then
child[method] = value
end
end
end
return child
end
local function signed_index(t, n)
return n and n <= 0 and #t + 1 + n or n
end
local function is_node(value)
if value == nil then
return false
end
local mt = getmetatable(value)
return not (mt == nil or node_classes[mt] == nil)
end
local function node_class(value)
if value == nil then
return nil
end
local mt = getmetatable(value)
if mt == nil then
return nil
end
return mt ~= nil and node_classes[mt] or nil
end
local function class_else_type(value)
if value == nil then
return type(value)
end
local mt = getmetatable(value)
if mt == nil then
return type(value)
end
local class = node_classes[mt]
return class == nil and type(value) or class
end
-- Recursively calling tostring() adds to the C stack (limit: 200), whereas
-- calling __tostring metamethods directly does not. Occasionally relevant when
-- dealing with very deep nesting.
local tostring
do
local _tostring = _G.tostring
function tostring(value)
if is_node(value) then
return value:__tostring(value)
end
return _tostring(value)
end
end
------------------------------------------------------------------------------------
--
-- Nodes
--
------------------------------------------------------------------------------------
local Node = {}
Node.__index = Node
function Node:next(i)
i = i + 1
return self[i], self, i
end
--[==[
Implements recursive iteration over a node tree.
By default, when a node is encountered (which may contain other nodes), it is returned on the first iteration, and then any child nodes are returned on each subsequent iteration; the same process is then followed if any of those children contain nodes themselves. Once a particular node has been fully traversed, the iterator then continues with any sibling nodes. The iterator will use the `next` method of each node to traverse it, which may differ depending on the node class.
Each iteration returns three values: `value`, `node` and `key`. Together, these can be used to manipulate the node tree at any given point without needing to know the full structure. Note that when the input node is returned on the first iteration, `node` and `key` will be nil.
The optional argument `test` can be used to limit the return values. This should be a function that returns a boolean value, where a return value of true means that the child will be returned by the iterator. If a node is not returned by the iterator, it will still be traversed, as it may contain children that should be returned.
The method `iterate_nodes` is provided as a special instance of iterate which uses `is_node` as the test.]==]
function Node:iterate(test)
local node, k, n, nodes, keys, returned_self = self, 0, 0
-- Special case if `test` is `is_node`.
local is_node_is_test = test == is_node
return function()
if not returned_self then
returned_self = true
if test == nil or test(self) then
return self
end
end
-- Get `v`, which is the value at the last-returned key of the current node; if `v` is a node, it will be iterated over (i.e. recursive iteration). By default, `v` will be the last-returned value, but looking it up here means that any modifications made to the node during the loop will be taken into account. This makes it possible to swap one node out for something else (e.g. another node), or to remove it entirely, without being locked into recursively iterating over the old node; instead, the new node (if any) will be iterated over. This means node trees can be modified on-the-fly during the course of a single loop.
local v, node_check = node[k], true
while true do
-- If `v` is a node, memoize the current node and key, then iterate over it.
if node_check and is_node(v) then
-- `n` is the current memo level.
n = n + 1
if nodes then
nodes[n], keys[n] = node, k
else
nodes, keys = {node}, {k}
end
node, k = v, 0
end
v, node, k = node:next(k)
-- If `v` is nil, move down one level, then continue iterating the node on that level (if any), or otherwise terminate the loop.
if v == nil then
if n == 0 then
return nil
end
node, k, n = nodes[n], keys[n], n - 1
elseif test == nil or test(v) then
return v, node, k
-- If `test` is `is_node`, there's no point checking it again on the next loop.
elseif node_check and is_node_is_test then
node_check = false
end
end
end
end
function Node:iterate_nodes(...)
local args_n = select("#", ...)
if args_n == 0 then
return self:iterate(is_node)
elseif args_n == 1 then
local class = ...
return self:iterate(function(value)
return node_class(value) == class
end)
end
local classes = {}
for i = 1, args_n do
classes[select(i, ...)] = true
end
return self:iterate(function(value)
return classes[node_class(value)]
end)
end
function Node:__tostring()
local output = {}
for i = 1, #self do
insert(output, tostring(self[i]))
end
return concat(output)
end
function Node:clone()
return deep_copy(self, "keep", true)
end
function Node:new_class(class)
local t = {type = class}
t.__index = t
t = inherit_metamethods(t, self)
node_classes[t] = class
return setmetatable(t, self)
end
function Node:new(t)
rawset(t, "_parse_data", nil)
return setmetatable(t, self)
end
do
local Proxy = {}
function Proxy:__index(k)
local v = Proxy[k]
if v ~= nil then
return v
end
return self.__chars[k]
end
function Proxy:__newindex(k, v)
local key = self.__keys[k]
if key then
self.__chars[k] = v
self.__parents[key] = v
elseif key == false then
error("Character is immutable.")
else
error("Invalid key.")
end
end
function Proxy:build(a, b, c)
local len = self.__len + 1
self.__chars[len] = a
self.__parents[len] = b
self.__keys[len] = c
self.__len = len
end
function Proxy:iter(i)
i = i + 1
local char = self.__chars[i]
if char ~= nil then
return i, self[i], self, self.__parents[i], self.__keys[i]
end
end
function Node:new_proxy()
return setmetatable({
__node = self,
__chars = {},
__parents = {},
__keys = {},
__len = 0
}, Proxy)
end
end
function export.node()
return Node:new_class("node")
end
------------------------------------------------------------------------------------
--
-- Parser
--
------------------------------------------------------------------------------------
local Parser = {}
Parser.__index = Parser
function Parser:get_layer(n)
if n ~= nil then
return rawget(self, #self + n)
end
return self.current_layer
end
function Parser:emit(a, b)
local layer = self.current_layer
if b ~= nil then
insert(layer, signed_index(layer, a), b)
else
rawset(layer, #layer + 1, a)
end
end
function Parser:emit_tokens(a, b)
local layer = self.current_layer
if b ~= nil then
a = signed_index(layer, a)
for i = 1, #b do
insert(layer, a + i - 1, b[i])
end
else
local len = #layer
for i = 1, #a do
len = len + 1
rawset(layer, len, a[i])
end
end
end
function Parser:remove(n)
local layer = self.current_layer
if n ~= nil then
return remove(layer, signed_index(layer, n))
end
local len = #layer
local token = layer[len]
layer[len] = nil
return token
end
function Parser:replace(a, b)
local layer = self.current_layer
layer[signed_index(layer, a)] = b
end
-- Unlike default table.concat, this respects __tostring metamethods.
function Parser:concat(a, b, c)
if a == nil or a > 0 then
return self:concat(0, a, b)
end
local layer, ret, n = self:get_layer(a), {}, 0
for i = b and signed_index(layer, b) or 1, c and signed_index(layer, c) or #layer do
n = n + 1
ret[n] = tostring(layer[i])
end
return concat(ret)
end
function Parser:emitted(delta)
if delta == nil then
delta = -1
end
local get_layer, i = self.get_layer, 0
while true do
local layer = get_layer(self, i)
if layer == nil then
return nil
end
local layer_len = #layer
if -delta <= layer_len then
return rawget(layer, layer_len + delta + 1)
end
delta = delta + layer_len
i = i - 1
end
end
function Parser:push(route)
local layer = {_parse_data = {
head = self.head,
route = route,
}}
self[#self + 1] = layer
self.current_layer = layer
end
function Parser:push_sublayer(handler, inherit)
local pdata = {
handler = handler,
sublayer = true,
}
local sublayer = {
_parse_data = pdata,
}
if inherit then
local layer_parse_data = self.current_layer._parse_data
setmetatable(pdata, inherit_metamethods({
__index = layer_parse_data,
__newindex = layer_parse_data
}, getmetatable(layer_parse_data)))
end
self[#self + 1] = sublayer
self.current_layer = sublayer
end
function Parser:pop()
local len, layer = #self
while true do
layer = self[len]
self[len] = nil
len = len - 1
if len == 0 then
self.current_layer = self
break
elseif layer._parse_data.sublayer == nil then
self.current_layer = self[len]
break
end
self:emit_tokens(layer)
end
return setmetatable(layer, nil)
end
function Parser:pop_sublayer()
local len, layer = #self, self.current_layer
self[len] = nil
self.current_layer = len == 1 and self or self[len - 1]
return setmetatable(layer, nil)
end
function Parser:get(route, ...)
self:push(route)
local layer = route(self, ...)
if layer == nil then
layer = self:traverse()
end
return layer
end
function Parser:try(route, ...)
local failed_routes = self.failed_routes
if failed_routes ~= nil then
local failed_layer = get_nested(failed_routes, route, self.head)
if failed_layer ~= nil then
return false, failed_layer
end
end
local layer = self:get(route, ...)
return not layer._parse_data.fail, layer
end
function Parser:fail_route()
local layer = self:pop()
local pdata = layer._parse_data
pdata.fail = true
local layer_head = pdata.head
set_nested(self, layer, "failed_routes", pdata.route, layer_head)
self.head = layer_head
return layer
end
function Parser:traverse()
local consume, advance = self.consume, self.advance
while true do
local layer = consume(self)
if layer ~= nil then
return layer
end
advance(self)
end
end
-- Converts a handler into a switch table the first time it's called, which avoids creating unnecessary objects, and prevents any scoping issues caused by parser methods being assigned to table keys before they've been declared.
-- false is used as the default key.
do
local Switch = {}
function Switch:__call(parser, this)
return (self[this] or self[false])(parser, this)
end
function Parser:switch(func, t)
local pdata = self.current_layer._parse_data
-- Point handler to the new switch table if the calling function is the current handler.
if pdata.handler == func then
pdata.handler = t
end
return setmetatable(t, Switch)
end
end
-- Generate a new parser class object, which is used as the template for any parser objects. These should be customized with additional/modified methods as needed.
function Parser:new_class()
local t = {}
t.__index = t
return setmetatable(inherit_metamethods(t, self), self)
end
-- Generate a new parser object, which is used for a specific parse.
function Parser:new(text)
return setmetatable({
text = text,
head = 1
}, self)
end
function Parser:parse(data)
local parser = self:new(data.text)
local success, tokens = parser:try(unpack(data.route))
if #parser > 0 then
-- This shouldn't happen.
error("Parser exited with non-empty stack.")
elseif success then
local node = data.node
return true, node[1]:new(tokens, unpack(node, 2)), parser
elseif data.allow_fail then
return false, nil, parser
end
error("Parser exited with failed route.")
end
export.class_else_type = class_else_type
export.is_node = is_node
export.tostring = tostring
local ArrayParser = Parser:new_class()
function ArrayParser:read(delta)
local v = self.text[self.head + (delta or 0)]
return v == nil and "" or v
end
function ArrayParser:advance(n)
self.head = self.head + (n == nil and 1 or n)
end
function ArrayParser:jump(head)
self.head = head
end
function ArrayParser:consume(this, ...)
if this == nil then
this = self:read()
end
local pdata = self.current_layer._parse_data
return pdata.handler(self, this, ...)
end
function export.array_parser()
return ArrayParser:new_class()
end
local StringParser = Parser:new_class()
function StringParser:read(i, j)
local head, i = self.head, i or 0
return sub(self.text, head + i, head + (j or i))
end
function StringParser:advance(n)
self.head = self.head + (n or self.current_layer._parse_data.step or 1)
end
function StringParser:jump(head)
local pdata = self.current_layer._parse_data
self.head, pdata.next, pdata.next_len = head, nil, nil
end
-- If `ignore_nonmatch` is set, any non-match segment before the match will be ignored.
function StringParser:set_pattern(pattern, ignore_nonmatch)
local pdata = self.current_layer._parse_data
pdata.pattern, pdata.next, pdata.next_len = "(" .. pattern .. ")", nil, nil
if ignore_nonmatch then
pdata.ignore_nonmatch = true
end
end
function StringParser:consume()
local pdata = self.current_layer._parse_data
local this = pdata.next
-- Use `next` and `next_len` from the previous iteration, if available.
if this then
pdata.step, pdata.next, pdata.next_len = pdata.next_len, nil, nil
return pdata.handler(self, this)
end
local text, head, loc1, loc2 = self.text, self.head
loc1, loc2, this = find(text, pdata.pattern, head)
-- If there was no match, default to find(text, "$", head), with `this` as
-- the empty string.
if not loc1 then
this, loc1 = "", #text + 1
loc2 = loc1 - 1 -- zero-length matches cause loc2 to be less than loc1
end
-- If `this` is at `head`, consume it.
if loc1 == head then
pdata.step = loc2 - loc1 + 1
-- If `ignore_nonmatch` is set, ignore everything before `this`, then
-- consume it.
elseif pdata.ignore_nonmatch then
self.head, pdata.step = loc1, loc2 - loc1 + 1
-- Otherwise, consume everything before `this`, and memoize the match and
-- match length; the length is dealt with separately, as it could be 0 if
-- `next` is an index (e.g. if the pattern is the empty string).
else
this, pdata.step, pdata.next, pdata.next_len = sub(text, head, loc1 - 1), loc1 - head, this, loc2 - loc1 + 1
end
return pdata.handler(self, this)
end
function export.string_parser()
return StringParser:new_class()
end
return export
itvslgsv46c1ywldkt63xzu5krykaov
218846
218845
2025-06-20T00:30:14Z
Sponge2490
8927
Membatalkan semakan [[Special:Diff/218845|218845]] oleh [[Special:Contributions/Sponge2490|Sponge2490]] ([[User talk:Sponge2490|perbincangan]]) Ralat
218846
Scribunto
text/plain
local export = {}
local concat = table.concat
local deepcopy -- Assigned when needed.
local getmetatable = getmetatable
local insert = table.insert
local next = next
local rawget = rawget
local rawset = rawset
local remove = table.remove
local select = select
local setmetatable = setmetatable
local type = type
local unpack = unpack
local classes = {}
local metamethods = mw.loadData("Module:data/metamethods")
------------------------------------------------------------------------------------
--
-- Helper functions
--
------------------------------------------------------------------------------------
local function get_nested(a, b, ...)
if not a then
return nil
elseif ... then
return get_nested(a[b], ...)
end
return a[b]
end
local function set_nested(a, b, c, ...)
if not (a and b) then
return
elseif c and ... then
a[b] = a[b] or {}
return set_nested(a[b], c, ...)
end
a[b] = c
end
local function inherit_metamethods(child, parent)
if parent then
for method, value in next, parent do
if child[method] == nil and metamethods[method] then
child[method] = value
end
end
end
return child
end
local function signed_index(t, n)
return n and n <= 0 and #t + 1 + n or n
end
local function is_node(value)
return classes[getmetatable(value)] and true or false
end
-- Recursively calling tostring() adds to the C stack (limit: 200), whereas
-- calling __tostring metamethods directly does not. Occasionally relevant when
-- dealing with very deep nesting.
local tostring
do
local _tostring = _G.tostring
function tostring(value)
if is_node(value) then
return value:__tostring(value)
end
return _tostring(value)
end
end
local function class_else_type(value)
return classes[getmetatable(value)] or type(value)
end
------------------------------------------------------------------------------------
--
-- Nodes
--
------------------------------------------------------------------------------------
local Node = {}
Node.__index = Node
function Node:next(i)
i = i + 1
return self[i], i
end
function Node:next_node(i)
local v
repeat
v, i = self:next(i)
until v == nil or is_node(v)
return v, i
end
-- Implements recursive iteration over a node tree, using functors to maintain state (which uses a lot less memory than closures). Iterator1 exists only to return the calling node on the first iteration, while Iterator2 uses a stack to store the state of each layer in the tree.
-- When a node is encountered (which may contain other nodes), it is returned on the first iteration, and then any child nodes are returned on each subsequent iteration; the same process is followed if any of those children contain nodes themselves. Once a particular node has been fully traversed, the iterator moves back up one layer and continues with any sibling nodes.
-- Each iteration returns three values: `value`, `node` and `key`. Together, these can be used to manipulate the node tree at any given point without needing to know the full structure. Note that when the input node is returned on the first iteration, `node` and `key` will be nil.
-- By default, the iterator will use the `next` method of each node, but this can be changed with the `next_func` parameter, which accepts a string argument with the name of a next method. This is because trees might consist of several different classes of node, and each might have different next methods that are tailored to their particular structures. In addition, each class of node might have multiple different next methods, which can be named according to their purposes. `next_func` ensures that the iterator uses equivalent next methods between different types of node.
-- Currently, two next methods are available: `next`, which simply iterates over the node conventionally, and `next_node`, which only returns children that are themselves nodes. Custom next methods can be declared by any calling module.
do
local Iterator1, Iterator2 = {}, {}
Iterator1.__index = Iterator2 -- Not a typo.
Iterator2.__index = Iterator2
function Iterator1:__call()
setmetatable(self, Iterator2)
return self[1].node
end
function Iterator2:push(node)
local layer = {
k = 0,
node = node
}
self[#self + 1] = layer
self[-1] = layer
return self
end
function Iterator2:pop()
local len = #self
self[len] = nil
self[-1] = self[len - 1]
end
function Iterator2:catch_values(node, ...)
local v, k = ...
if v == nil then
self:pop()
if self[-1] then
return self:__call()
end
return
end
self[-1].k = k
if is_node(v) then
self:push(v)
end
return v, node, select(2, ...)
end
function Iterator2:__call()
local layer = self[-1]
local node = layer.node
return self:catch_values(node, node[self.next_func](node, layer.k))
end
function Node:__pairs(next_func)
return setmetatable({
next_func = next_func or "next"
}, Iterator1):push(self)
end
end
function Node:rawpairs()
return next, self
end
function Node:__tostring()
local output = {}
for i = 1, #self do
insert(output, tostring(self[i]))
end
return concat(output)
end
function Node:clone()
if not deepcopy then
deepcopy = require("Module:table").deepcopy
end
return deepcopy(self, "keep", true)
end
function Node:new_class(class)
local t = {type = class}
t.__index = t
t = inherit_metamethods(t, self)
classes[t] = class
return setmetatable(t, self)
end
Node.keys_to_remove = {"fail", "handler", "head", "override", "route"}
function Node:new(t)
setmetatable(t, nil)
local keys_to_remove = self.keys_to_remove
for i = 1, #keys_to_remove do
t[keys_to_remove[i]] = nil
end
return setmetatable(t, self)
end
do
local Proxy = {}
function Proxy:__index(k)
return Proxy[k] or self.__chars[k]
end
function Proxy:__newindex(k, v)
local key = self.__keys[k]
if key then
self.__chars[k] = v
self.__parents[key] = v
elseif key == false then
error("Character is immutable.")
else
error("Invalid key.")
end
end
function Proxy:build(a, b, c)
local len = self.__len + 1
self.__chars[len] = a
self.__parents[len] = b
self.__keys[len] = c
self.__len = len
end
function Proxy:iter(i)
i = i + 1
local char = self.__chars[i]
if char then
return i, self[i], self, self.__parents[i], self.__keys[i]
end
end
function Node:new_proxy()
return setmetatable({
__node = self,
__chars = {},
__parents = {},
__keys = {},
__len = 0
}, Proxy)
end
end
------------------------------------------------------------------------------------
--
-- Parser
--
------------------------------------------------------------------------------------
local Parser = {}
Parser.__index = Parser
function Parser:read(delta)
return self.text[self.head + (delta or 0)] or ""
end
function Parser:advance(n)
self.head = self.head + (n or 1)
end
function Parser:layer(n)
if n then
return rawget(self, #self + n)
end
return self[-1]
end
function Parser:emit(a, b)
local layer = self[-1]
if b then
insert(layer, signed_index(layer, a), b)
else
rawset(layer, #layer + 1, a)
end
end
function Parser:emit_tokens(a, b)
local layer = self[-1]
if b then
a = signed_index(layer, a)
for i = 1, #b do
insert(layer, a + i - 1, b[i])
end
else
local len = #layer
for i = 1, #a do
len = len + 1
rawset(layer, len, a[i])
end
end
end
function Parser:remove(n)
local layer = self[-1]
if n then
return remove(layer, signed_index(layer, n))
end
local len = #layer
local token = layer[len]
layer[len] = nil
return token
end
function Parser:replace(a, b)
local layer = self[-1]
layer[signed_index(layer, a)] = b
end
-- Unlike default table.concat, this respects __tostring metamethods.
function Parser:concat(a, b, c)
if not a or a > 0 then
return self:concat(0, a, b)
end
local layer = self:layer(a)
local ret = {}
for i = signed_index(layer, b) or 1, signed_index(layer, c) or #layer do
insert(ret, tostring(layer[i]))
end
return concat(ret)
end
function Parser:emitted(delta)
delta = delta or -1
local i = 0
while true do
local layer = self:layer(i)
if not layer then
return nil
end
local layer_len = #layer
if -delta <= layer_len then
return rawget(layer, layer_len + delta + 1)
end
delta = delta + layer_len
i = i - 1
end
end
function Parser:push(route)
local layer = {
head = self.head,
route = route
}
self[#self + 1] = layer
self[-1] = layer
end
function Parser:push_sublayer(handler, inherit)
local sublayer = {
handler = handler,
sublayer = true
}
if inherit then
local layer = self[-1]
setmetatable(sublayer, inherit_metamethods({
__index = layer,
__newindex = layer
}, getmetatable(layer)))
end
self[#self + 1] = sublayer
self[-1] = sublayer
end
function Parser:pop()
local len, layer = #self
while true do
layer = self[len]
self[len] = nil
len = len - 1
self[-1] = self[len] or self
if not layer.sublayer then
break
end
self:emit_tokens(layer)
end
return layer
end
function Parser:pop_sublayer()
local len, layer = #self, self[-1]
self[len] = nil
self[-1] = self[len - 1] or self
setmetatable(layer, nil)
layer.sublayer = nil
return layer
end
function Parser:get(route, ...)
local failed_route = get_nested(self.failed_routes, self.head, route)
if failed_route then
return false, failed_route
end
self:push(route)
local layer = self[route](self, ...)
if layer == nil then
layer = self:traverse()
end
if layer.fail then
return false, layer
end
return true, layer
end
function Parser:consume(this, ...)
local layer = self[-1]
return (layer.override or layer.handler)(self, this or self:read(), ...)
end
function Parser:fail_route()
local layer = self:pop()
layer.fail = true
set_nested(self, "failed_routes", layer.head, layer.route, layer)
self.head = layer.head
return layer
end
function Parser:traverse()
while true do
local layer = self:consume()
if layer then
return layer
end
self:advance()
end
end
-- Converts a handler into a switch table the first time it's called, which avoids creating unnecessary objects, and prevents any scoping issues caused by parser methods being assigned to table keys before they've been declared.
-- false is used as the default key.
do
local Switch = {}
function Switch:__call(parser, this)
return (self[this] or self[false])(parser, this)
end
function Parser:switch(func, t)
local layer = self[-1]
-- Point handler to the new switch table if the calling function is the current handler.
if layer.handler == func then
layer.handler = t
end
return setmetatable(t, Switch)
end
end
-- Generate a new parser class object, which is used as the template for any parser objects. These should be customized with additional/modified methods as needed.
function Parser:new_class()
local t = {}
t.__index = t
return setmetatable(inherit_metamethods(t, self), self)
end
-- Generate a new parser object, which is used for a specific parse.
function Parser:new(text)
return setmetatable({
text = text,
head = 1
}, self)
end
function Parser:parse(data)
local parser = self:new(data.text)
local success, tokens = parser:get(unpack(data.route))
if #parser > 0 then
-- This shouldn't happen.
error("Parser exited with non-empty stack.")
elseif success then
local node = data.node
return true, node[1]:new(tokens, unpack(node, 2)), parser
elseif data.allow_fail then
return false, nil, parser
end
error("Parser exited with bad route.")
end
export.class_else_type = class_else_type
export.is_node = is_node
export.tostring = tostring
function export.new()
return Parser:new_class(), Node:new_class("node")
end
return export
m8ca5vsf65kudx5ne22s4knpb1xrwj6
Modul:data/magic words
828
51770
218844
184805
2025-06-20T00:01:48Z
Sponge2490
8927
Mengemaskini berdasarkan Module:data/magic words pada 20 Febuari 2025 (83987375)
218844
Scribunto
text/plain
local next = next
local date_and_time = "mw:Help:Magic words#Date and time"
local escaped_characters = "mw:Help:Magic words#Escaped characters"
local formatting = "mw:Help:Magic words#Formatting"
local labeled_section_transclusion = "mw:Extension:Labeled Section Transclusion"
local liquidthreads = "mw:Extension:LiquidThreads"
local localization_functions = "mw:Help:Magic words#Localization functions"
local localization_variables = "mw:Help:Magic words#Localization variables"
local miscellaneous = "mw:Help:Magic words#Miscellaneous"
local namespaces = "mw:Help:Magic words#Namespaces"
local namespaces_2 = "mw:Help:Magic words#Namespaces 2"
local noexternallanglinks = "mw:Wikibase/Installation/Advanced configuration#noexternallanglinks"
local page_names = "mw:Help:Magic words#Page names"
local parser_functions_ext = "mw:Help:Extension:ParserFunctions##" -- ## is not a typo
local statistics = "mw:Help:Magic words#Statistics"
local substitution = "mw:Manual:Substitution"
local technical_metadata = "mw:Help:Magic words#Technical metadata"
local technical_metadata_of_another_page = "mw:Help:Magic words#Technical metadata of another page"
local transclusion_modifiers = "mw:Help:Magic words#Transclusion modifiers"
local url_data = "mw:Help:Magic words#URL data"
local data = {}
for k, v in next, {
["!"] = {
parser_variable = escaped_characters,
case_sensitive = false
},
["#BABEL"] = {
parser_function = "mw:Extension:Babel#Usage",
case_sensitive = false
},
["#bcp47"] = { -- Case-sensitive lowercase.
parser_function = localization_functions,
parser_variable = localization_functions, -- Not a typo.
case_sensitive = true
},
["#CATEGORYTREE"] = {
parser_function = "mw:Extension:CategoryTree#The {{#categorytree}} parser function",
case_sensitive = false
},
["#COMMASEPARATEDLIST"] = {
parser_function = formatting,
case_sensitive = false
},
["#dir"] = { -- Case-sensitive lowercase.
parser_function = localization_functions,
parser_variable = localization_functions, -- Not a typo.
case_sensitive = true
},
["#EXPR"] = {
parser_function = parser_functions_ext .. "expr",
case_sensitive = false
},
["#FORMAL"] = {
parser_function = localization_functions,
case_sensitive = true
},
["#FORMATDATE"] = {
aliases = {"#DATEFORMAT"},
parser_function = formatting,
case_sensitive = false
},
["#IF"] = {
parser_function = parser_functions_ext .. "if",
case_sensitive = false
},
["#IFEQ"] = {
parser_function = parser_functions_ext .. "ifeq",
case_sensitive = false
},
["#IFERROR"] = {
parser_function = parser_functions_ext .. "iferror",
case_sensitive = false
},
["#IFEXIST"] = {
parser_function = parser_functions_ext .. "ifexist",
case_sensitive = false
},
["#IFEXPR"] = {
parser_function = parser_functions_ext .. "ifexpr",
case_sensitive = false
},
["#interlanguagelink"] = { -- Case-sensitive lowercase.
parser_function = miscellaneous,
case_sensitive = true
},
["#interwikilink"] = { -- Case-sensitive lowercase.
parser_function = miscellaneous,
case_sensitive = true
},
["#INVOKE"] = {
parser_function = "mw:Extension:Scribunto#Usage",
case_sensitive = false
},
["#LANGUAGE"] = {
parser_function = localization_functions,
parser_variable = localization_functions, -- Not a typo.
case_sensitive = false
},
["#LQTPAGELIMIT"] = {
parser_function = liquidthreads,
case_sensitive = false
},
["#LST"] = {
aliases = {"#SECTION"},
parser_function = labeled_section_transclusion,
case_sensitive = false
},
["#LSTH"] = {
aliases = {"#SECTION-H"},
parser_function = labeled_section_transclusion,
case_sensitive = false
},
["#LSTX"] = {
aliases = {"#SECTION-X"},
parser_function = labeled_section_transclusion,
case_sensitive = false
},
["#PROPERTY"] = {
parser_function = "m:Wikidata/Notes/Inclusion syntax",
case_sensitive = false
},
["#REL2ABS"] = {
parser_function = parser_functions_ext .. "rel2abs",
case_sensitive = false
},
["#SPECIAL"] = {
parser_function = miscellaneous,
case_sensitive = false
},
["#SPECIALE"] = {
parser_function = miscellaneous,
case_sensitive = false
},
["#STATEMENTS"] = {
parser_function = "d:WD:How to use data on Wikimedia projects#Parser function",
case_sensitive = false
},
["#SWITCH"] = {
parser_function = parser_functions_ext .. "switch",
case_sensitive = false
},
["#TAG"] = {
parser_function = miscellaneous,
case_sensitive = false
},
["#TARGET"] = {
parser_function = "mw:Extension:MassMessage#Parser function delivery lists",
case_sensitive = false
},
["#TIME"] = {
parser_function = parser_functions_ext .. "time",
case_sensitive = false
},
["#timef"] = { -- Case-sensitive lowercase.
parser_function = parser_functions_ext,
case_sensitive = true
},
["#timefl"] = { -- Case-sensitive lowercase.
parser_function = parser_functions_ext,
case_sensitive = true
},
["#TIMEL"] = {
parser_function = parser_functions_ext .. "timel",
case_sensitive = false
},
["#TITLEPARTS"] = {
parser_function = parser_functions_ext .. "titleparts",
case_sensitive = false
},
["#USELIQUIDTHREADS"] = {
parser_function = liquidthreads,
case_sensitive = false
},
["="] = {
parser_variable = escaped_characters,
case_sensitive = false
},
["ANCHORENCODE"] = {
parser_function = url_data,
case_sensitive = false
},
["ARTICLEPATH"] = {
parser_variable = technical_metadata,
case_sensitive = false
},
["BASEPAGENAME"] = {
parser_function = page_names,
parser_variable = page_names,
case_sensitive = true
},
["BASEPAGENAMEE"] = {
parser_function = page_names,
parser_variable = page_names,
case_sensitive = true
},
["BIDI"] = {
parser_function = formatting,
case_sensitive = false
},
["CANONICALURL"] = {
parser_function = url_data,
case_sensitive = false
},
["CANONICALURLE"] = {
parser_function = url_data,
case_sensitive = false
},
["CASCADINGSOURCES"] = {
parser_function = technical_metadata_of_another_page,
parser_variable = technical_metadata,
case_sensitive = true
},
["CONTENTLANGUAGE"] = {
aliases = {"CONTENTLANG"},
parser_variable = technical_metadata,
case_sensitive = true
},
["CURRENTDAY"] = {
parser_variable = date_and_time,
case_sensitive = true
},
["CURRENTDAY2"] = {
parser_variable = date_and_time,
case_sensitive = true
},
["CURRENTDAYNAME"] = {
parser_variable = date_and_time,
case_sensitive = true
},
["CURRENTDOW"] = {
parser_variable = date_and_time,
case_sensitive = true
},
["CURRENTHOUR"] = {
parser_variable = date_and_time,
case_sensitive = true
},
["CURRENTMONTH"] = {
aliases = {"CURRENTMONTH2"},
parser_variable = date_and_time,
case_sensitive = true
},
["CURRENTMONTH1"] = {
parser_variable = date_and_time,
case_sensitive = true
},
["CURRENTMONTHABBREV"] = {
parser_variable = date_and_time,
case_sensitive = true
},
["CURRENTMONTHNAME"] = {
parser_variable = date_and_time,
case_sensitive = true
},
["CURRENTMONTHNAMEGEN"] = {
parser_variable = date_and_time,
case_sensitive = true
},
["CURRENTTIME"] = {
parser_variable = date_and_time,
case_sensitive = true
},
["CURRENTTIMESTAMP"] = {
parser_variable = date_and_time,
case_sensitive = true
},
["CURRENTVERSION"] = {
parser_variable = technical_metadata,
case_sensitive = true
},
["CURRENTWEEK"] = {
parser_variable = date_and_time,
case_sensitive = true
},
["CURRENTYEAR"] = {
parser_variable = date_and_time,
case_sensitive = true
},
["DEFAULTSORT"] = {
aliases = {"DEFAULTCATEGORYSORT", "DEFAULTSORTKEY"},
parser_function = technical_metadata,
case_sensitive = true
},
["DIRECTIONMARK"] = {
aliases = {"DIRMARK"},
parser_variable = technical_metadata,
case_sensitive = true
},
["DISPLAYTITLE"] = {
parser_function = technical_metadata,
case_sensitive = true
},
["FILEPATH"] = {
parser_function = url_data,
case_sensitive = false
},
["FORMATNUM"] = {
parser_function = formatting,
case_sensitive = false
},
["FULLPAGENAME"] = {
parser_function = page_names,
parser_variable = page_names,
case_sensitive = true
},
["FULLPAGENAMEE"] = {
parser_function = page_names,
parser_variable = page_names,
case_sensitive = true
},
["FULLURL"] = {
parser_function = url_data,
case_sensitive = false
},
["FULLURLE"] = {
parser_function = url_data,
case_sensitive = false
},
["GENDER"] = {
parser_function = localization_functions,
case_sensitive = false
},
["GRAMMAR"] = {
parser_function = localization_functions,
case_sensitive = false
},
["INT"] = {
parser_function = localization_functions,
case_sensitive = false
},
["LC"] = {
parser_function = formatting,
case_sensitive = false
},
["LCFIRST"] = {
parser_function = formatting,
case_sensitive = false
},
["LOCALDAY"] = {
parser_variable = date_and_time,
case_sensitive = true
},
["LOCALDAY2"] = {
parser_variable = date_and_time,
case_sensitive = true
},
["LOCALDAYNAME"] = {
parser_variable = date_and_time,
case_sensitive = true
},
["LOCALDOW"] = {
parser_variable = date_and_time,
case_sensitive = true
},
["LOCALHOUR"] = {
parser_variable = date_and_time,
case_sensitive = true
},
["LOCALMONTH"] = {
aliases = {"LOCALMONTH2"},
parser_variable = date_and_time,
case_sensitive = true
},
["LOCALMONTH1"] = {
parser_variable = date_and_time,
case_sensitive = true
},
["LOCALMONTHABBREV"] = {
parser_variable = date_and_time,
case_sensitive = true
},
["LOCALMONTHNAME"] = {
parser_variable = date_and_time,
case_sensitive = true
},
["LOCALMONTHNAMEGEN"] = {
parser_variable = date_and_time,
case_sensitive = true
},
["LOCALTIME"] = {
parser_variable = date_and_time,
case_sensitive = true
},
["LOCALTIMESTAMP"] = {
parser_variable = date_and_time,
case_sensitive = true
},
["LOCALURL"] = {
parser_function = url_data,
case_sensitive = false
},
["LOCALURLE"] = {
parser_function = url_data,
case_sensitive = false
},
["LOCALWEEK"] = {
parser_variable = date_and_time,
case_sensitive = true
},
["LOCALYEAR"] = {
parser_variable = date_and_time,
case_sensitive = true
},
["MSG"] = {
transclusion_modifier = transclusion_modifiers,
priority = 2,
case_sensitive = false
},
["MSGNW"] = {
transclusion_modifier = transclusion_modifiers,
priority = 2,
case_sensitive = false
},
["NAMESPACE"] = {
parser_function = namespaces,
parser_variable = namespaces,
case_sensitive = true
},
["NAMESPACEE"] = {
parser_function = namespaces,
parser_variable = namespaces,
case_sensitive = true
},
["NAMESPACENUMBER"] = {
parser_function = namespaces,
parser_variable = namespaces,
case_sensitive = true
},
["NOEXTERNALLANGLINKS"] = {
parser_function = noexternallanglinks,
parser_variable = noexternallanglinks,
case_sensitive = false
},
["NS"] = {
parser_function = namespaces_2,
case_sensitive = false
},
["NSE"] = {
parser_function = namespaces_2,
case_sensitive = false
},
["NUMBERINGROUP"] = {
aliases = {"NUMINGROUP"},
parser_function = statistics,
case_sensitive = true
},
["NUMBEROFACTIVEUSERS"] = {
parser_function = statistics,
parser_variable = statistics,
case_sensitive = true
},
["NUMBEROFADMINS"] = {
parser_function = statistics,
parser_variable = statistics,
case_sensitive = true
},
["NUMBEROFARTICLES"] = {
parser_function = statistics,
parser_variable = statistics,
case_sensitive = true
},
["NUMBEROFEDITS"] = {
parser_function = statistics,
parser_variable = statistics,
case_sensitive = true
},
["NUMBEROFFILES"] = {
parser_function = statistics,
parser_variable = statistics,
case_sensitive = true
},
["NUMBEROFPAGES"] = {
parser_function = statistics,
parser_variable = statistics,
case_sensitive = true
},
["NUMBEROFUSERS"] = {
parser_function = statistics,
parser_variable = statistics,
case_sensitive = true
},
["PADLEFT"] = {
parser_function = formatting,
case_sensitive = false
},
["PADRIGHT"] = {
parser_function = formatting,
case_sensitive = false
},
["PAGEID"] = {
parser_function = technical_metadata_of_another_page,
parser_variable = technical_metadata,
case_sensitive = false
},
["PAGELANGUAGE"] = {
parser_variable = technical_metadata,
case_sensitive = true
},
["PAGENAME"] = {
parser_function = page_names,
parser_variable = page_names,
case_sensitive = true
},
["PAGENAMEE"] = {
parser_function = page_names,
parser_variable = page_names,
case_sensitive = true
},
["PAGESINCATEGORY"] = {
aliases = {"PAGESINCAT"},
parser_function = statistics,
case_sensitive = true
},
["PAGESIZE"] = {
parser_function = technical_metadata_of_another_page,
case_sensitive = true
},
["PLURAL"] = {
parser_function = localization_functions,
case_sensitive = false
},
["PROTECTIONEXPIRY"] = {
parser_function = {
technical_metadata,
technical_metadata_of_another_page
},
case_sensitive = true
},
["PROTECTIONLEVEL"] = {
parser_function = {
technical_metadata,
technical_metadata_of_another_page
},
case_sensitive = true
},
["RAW"] = {
transclusion_modifier = transclusion_modifiers,
priority = 3,
case_sensitive = false
},
["REVISIONDAY"] = {
parser_function = technical_metadata_of_another_page,
parser_variable = technical_metadata,
case_sensitive = true
},
["REVISIONDAY2"] = {
parser_function = technical_metadata_of_another_page,
parser_variable = technical_metadata,
case_sensitive = true
},
["REVISIONID"] = {
parser_function = technical_metadata_of_another_page,
parser_variable = technical_metadata,
case_sensitive = true
},
["REVISIONMONTH"] = {
parser_function = technical_metadata_of_another_page,
parser_variable = technical_metadata,
case_sensitive = true
},
["REVISIONMONTH1"] = {
parser_function = technical_metadata_of_another_page,
parser_variable = technical_metadata,
case_sensitive = true
},
["REVISIONSIZE"] = {
parser_variable = technical_metadata,
case_sensitive = true
},
["REVISIONTIMESTAMP"] = {
parser_function = technical_metadata_of_another_page,
parser_variable = technical_metadata,
case_sensitive = true
},
["REVISIONUSER"] = {
parser_function = technical_metadata_of_another_page,
parser_variable = technical_metadata,
case_sensitive = true
},
["REVISIONYEAR"] = {
parser_function = technical_metadata_of_another_page,
parser_variable = technical_metadata,
case_sensitive = true
},
["ROOTPAGENAME"] = {
parser_function = page_names,
parser_variable = page_names,
case_sensitive = true
},
["ROOTPAGENAMEE"] = {
parser_function = page_names,
parser_variable = page_names,
case_sensitive = true
},
["SAFESUBST"] = {
transclusion_modifier = substitution,
priority = 1,
case_sensitive = false
},
["SCRIPTPATH"] = {
parser_variable = technical_metadata,
case_sensitive = false
},
["SERVER"] = {
parser_variable = technical_metadata,
case_sensitive = false
},
["SERVERNAME"] = {
parser_variable = technical_metadata,
case_sensitive = false
},
["SITENAME"] = {
parser_variable = technical_metadata,
case_sensitive = true
},
["STYLEPATH"] = {
parser_variable = technical_metadata,
case_sensitive = false
},
["SUBJECTPAGENAME"] = {
aliases = {"ARTICLEPAGENAME"},
parser_function = page_names,
parser_variable = page_names,
case_sensitive = true
},
["SUBJECTPAGENAMEE"] = {
aliases = {"ARTICLEPAGENAMEE"},
parser_function = page_names,
parser_variable = page_names,
case_sensitive = true
},
["SUBJECTSPACE"] = {
aliases = {"ARTICLESPACE"},
parser_function = namespaces,
parser_variable = namespaces,
case_sensitive = true
},
["SUBJECTSPACEE"] = {
aliases = {"ARTICLESPACEE"},
parser_function = namespaces,
parser_variable = namespaces,
case_sensitive = true
},
["SUBPAGENAME"] = {
parser_function = page_names,
parser_variable = page_names,
case_sensitive = true
},
["SUBPAGENAMEE"] = {
parser_function = page_names,
parser_variable = page_names,
case_sensitive = true
},
["SUBST"] = {
transclusion_modifier = substitution,
priority = 1,
case_sensitive = false
},
["TALKPAGENAME"] = {
parser_function = page_names,
parser_variable = page_names,
case_sensitive = true
},
["TALKPAGENAMEE"] = {
parser_function = page_names,
parser_variable = page_names,
case_sensitive = true
},
["TALKSPACE"] = {
parser_function = namespaces,
parser_variable = namespaces,
case_sensitive = true
},
["TALKSPACEE"] = {
parser_function = namespaces,
parser_variable = namespaces,
case_sensitive = true
},
["UC"] = {
parser_function = formatting,
case_sensitive = false
},
["UCFIRST"] = {
parser_function = formatting,
case_sensitive = false
},
["URLENCODE"] = {
parser_function = url_data,
case_sensitive = false
},
["USERLANGUAGE"] = {
parser_variable = localization_variables,
case_sensitive = true
},
} do
data[k] = v
if not v.name then
v.name = k
end
local aliases = v.aliases
if aliases then
for i = 1, #aliases do
data[aliases[i]] = v
end
v.aliases = nil
end
end
return data
jkwpl1ihlf560owi79olg91zvhvb1xy
Modul:require when needed
828
57635
218840
186131
2025-06-19T23:41:33Z
Sponge2490
8927
Mengemaskini berdasarkan Module:require when needed pada 24 April 2025 (84628829)
218840
Scribunto
text/plain
local getmetatable = getmetatable
local ipairs = ipairs
local loaded = package.loaded
local pairs = pairs
local require = require
local select = select
local setmetatable = setmetatable
local tostring = tostring
local unpack = unpack or table.unpack -- Lua 5.2 compatibility
local function get_nested(obj, ...)
local n = select("#", ...)
if n == 0 then
return obj
end
obj = obj[...]
for i = 2, n do
obj = obj[select(i, ...)]
end
return obj
end
local function get_obj(mt)
local obj = require(mt[1])
if #mt > 1 then
obj = get_nested(obj, unpack(mt, 2))
end
mt[0] = obj
return obj
end
local function __call(self, ...)
local mt = getmetatable(self)
local obj = mt[0]
if obj == nil then
obj = get_obj(mt)
end
return obj(...)
end
local function __index(self, k)
local mt = getmetatable(self)
local obj = mt[0]
if obj == nil then
obj = get_obj(mt)
end
return obj[k]
end
local function __ipairs(self)
local mt = getmetatable(self)
local obj = mt[0]
if obj == nil then
obj = get_obj(mt)
end
return ipairs(obj)
end
local function __newindex(self, k, v)
local mt = getmetatable(self)
local obj = mt[0]
if obj == nil then
obj = get_obj(mt)
end
obj[k] = v
end
local function __pairs(self)
local mt = getmetatable(self)
local obj = mt[0]
if obj == nil then
obj = get_obj(mt)
end
return pairs(obj)
end
local function __tostring(self)
local mt = getmetatable(self)
local obj = mt[0]
if obj == nil then
obj = get_obj(mt)
end
return tostring(obj)
end
return function(modname, ...)
local mod = loaded[modname]
if mod ~= nil then
return get_nested(mod, ...)
end
return setmetatable({}, {
modname,
__call = __call,
__index = __index,
__ipairs = __ipairs,
__newindex = __newindex,
__pairs = __pairs,
__tostring = __tostring,
-- TODO: other metamethods, if needed.
...
})
end
1p8upm5p2cm943t5atixatwvtsenpe2
Modul:pages
828
57817
218847
184808
2025-06-20T00:53:18Z
Sponge2490
8927
Mengemaskini berdasarkan Module:pages when needed pada 26 Mei 2025 (84947246)
218847
Scribunto
text/plain
local export = {}
local string_utilities_module = "Module:string utilities"
local concat = table.concat
local find = string.find
local format = string.format
local getmetatable = getmetatable
local get_current_section -- defined below
local get_namespace_shortcut -- defined below
local get_pagetype -- defined below
local gsub = string.gsub
local insert = table.insert
local is_internal_title -- defined below
local is_title -- defined below
local lower = string.lower
local match = string.match
local new_title = mw.title.new
local require = require
local sub = string.sub
local title_equals = mw.title.equals
local tonumber = tonumber
local type = type
local ufind = mw.ustring.find
local unstrip_nowiki = mw.text.unstripNoWiki
--[==[
Loaders for functions in other modules, which overwrite themselves with the target function when called. This ensures modules are only loaded when needed, retains the speed/convenience of locally-declared pre-loaded functions, and has no overhead after the first call, since the target functions are called directly in any subsequent calls.]==]
local function decode_entities(...)
decode_entities = require(string_utilities_module).decode_entities
return decode_entities(...)
end
local function ulower(...)
ulower = require(string_utilities_module).lower
return ulower(...)
end
local function trim(...)
trim = require(string_utilities_module).trim
return trim(...)
end
--[==[
Loaders for objects, which load data (or some other object) into some variable, which can then be accessed as "foo or get_foo()", where the function get_foo sets the object to "foo" and then returns it. This ensures they are only loaded when needed, and avoids the need to check for the existence of the object each time, since once "foo" has been set, "get_foo" will not be called again.]==]
local current_frame
local function get_current_frame()
current_frame, get_current_frame = mw.getCurrentFrame(), nil
return current_frame
end
local parent_frame
local function get_parent_frame()
parent_frame, get_parent_frame = (current_frame or get_current_frame()):getParent(), nil
return parent_frame
end
local namespace_shortcuts
local function get_namespace_shortcuts()
namespace_shortcuts, get_namespace_shortcuts = {
[4] = "WT",
[10] = "T",
[14] = "CAT",
[100] = "AP",
[110] = "WS",
[118] = "RC",
[828] = "MOD",
}, nil
return namespace_shortcuts
end
do
local transcluded
--[==[
Returns {true} if the current {{tl|#invoke:}} is being transcluded, or {false} if not. If the current {{tl|#invoke:}} is part of a template, for instance, this template will therefore return {true}.
Note that if a template containing an {{tl|#invoke:}} is used on its own page (e.g. to display a demonstration), this function is still able to detect that this is transclusion. This is an improvement over the other method for detecting transclusion, which is to check the parent frame title against the current page title, which fails to detect transclusion in that instance.]==]
function export.is_transcluded()
if transcluded == nil then
transcluded = (parent_frame or get_parent_frame()) and parent_frame:preprocess("<includeonly>1</includeonly>") == "1" or false
end
return transcluded
end
end
do
local preview
--[==[
Returns {true} if the page is currently being viewed in preview, or {false} if not.]==]
function export.is_preview()
if preview == nil then
preview = (current_frame or get_current_frame()):preprocess("{{REVISIONID}}") == ""
end
return preview
end
end
--[==[
Returns {true} if the input is a title object, or {false} if not. This therefore '''includes''' external title objects (i.e. those for pages on other wikis), such as [[w:Example]], unlike `is_internal_title` below.]==]
function export.is_title(val)
if not (val and type(val) == "table") then
return false
end
local mt = getmetatable(val)
-- There's no foolproof method for checking for a title object, but the
-- __eq metamethod should be mw.title.equals unless the object has been
-- seriously messed around with.
return mt and
type(mt) == "table" and
getmetatable(mt) == nil and
mt.__eq == title_equals and
true or false
end
is_title = export.is_title
--[==[
Returns {true} if the input is an internal title object, or {false} if not. An internal title object is a title object for a page on this wiki, such as [[example]]. This therefore '''excludes''' external title objects (i.e. those for pages on other wikis), such as [[w:Example]], unlike `is_title` above.]==]
function export.is_internal_title(title)
-- Note: Mainspace titles starting with "#" should be invalid, but a bug in mw.title.new and mw.title.makeTitle means a title object is returned that has the empty string for prefixedText, so they need to be filtered out.
return is_title(title) and #title.prefixedText > 0 and #title.interwiki == 0
end
is_internal_title = export.is_internal_title
--[==[
Returns {true} if the input string is a valid link target, or {false} if not. This therefore '''includes''' link targets to other wikis, such as [[w:Example]], unlike `is_valid_page_name` below.]==]
function export.is_valid_link_target(target)
local target_type = type(target)
if target_type == "string" then
return is_title(new_title(target))
end
error(format("bad argument #1 to 'is_valid_link_target' (string expected, got %s)", target_type), 2)
end
--[==[
Returns {true} if the input string is a valid page name on this wiki, or {false} if not. This therefore '''excludes''' page names on other wikis, such as [[w:Example]], unlike `is_valid_link_target` above.]==]
function export.is_valid_page_name(name)
local name_type = type(name)
if name_type == "string" then
return is_internal_title(new_title(name))
end
error(format("bad argument #1 to 'is_valid_page_name' (string expected, got %s)", name_type), 2)
end
--[==[
Given a title object, returns a full link target which will always unambiguously link to it.
For instance, the input {"foo"} (for the page [[foo]]) returns {":foo"}, as a leading colon always refers to mainspace, even when other namespaces might be assumed (e.g. when transcluding using `{{ }}` syntax).
If `shortcut` is set, then the returned target will use the namespace shortcut, if any; for example, the title for `Template:foo` would return {"T:foo"} instead of {"Template:foo"}.]==]
function export.get_link_target(title, shortcut)
if not is_title(title) then
error(format("bad argument #1 to 'is_valid_link_target' (title object expected, got %s)", type(title)))
elseif title.interwiki ~= "" then
return title.fullText
elseif shortcut then
local fragment = title.fragment
if fragment == "" then
return get_namespace_shortcut(title) .. ":" .. title.text
end
return get_namespace_shortcut(title) .. ":" .. title.text .. "#" .. fragment
elseif title.namespace == 0 then
return ":" .. title.fullText
end
return title.fullText
end
do
local function find_sandbox(text)
return find(text, "^User:.") or find(lower(text), "sandbox", 1, true)
end
local function get_transclusion_subtypes(title, main_type, documentation, page_suffix)
local text, subtypes = title.text, {main_type}
-- Any template/module with "sandbox" in the title. These are impossible
-- to screen for more accurately, as there's no consistent pattern. Also
-- any user sandboxes in the form (e.g.) "Template:User:...".
local sandbox = find_sandbox(text)
if sandbox then
insert(subtypes, "sandbox")
end
-- Any template/module testcases (which can be labelled and/or followed
-- by further subpages).
local testcase = find(text, "./[Tt]estcases?%f[%L]")
if testcase then
-- Order "testcase" and "sandbox" based on where the patterns occur
-- in the title.
local n = sandbox and sandbox < testcase and 3 or 2
insert(subtypes, n, "testcase")
end
-- Any template/module documentation pages.
if documentation then
insert(subtypes, "documentation")
end
local final = subtypes[#subtypes]
if not (final == main_type and not page_suffix or final == "sandbox") then
insert(subtypes, "page")
end
return concat(subtypes, " ")
end
local function get_snippet_subtypes(title, main_type, documentation)
local ns = title.namespace
return get_transclusion_subtypes(title, (
ns == 2 and "user " or
ns == 8 and match(title.text, "^Gadget-.") and "gadget " or
""
) .. main_type, documentation)
end
--[==[
Returns the page type of the input title object in a format which can be used in running text.]==]
function export.get_pagetype(title)
if not is_internal_title(title) then
error(mw.dumpObject(title.fullText) .. " is not a valid page name.")
end
-- If possibly a documentation page, get the base title and set the
-- `documentation` flag.
local content_model, text, documentation = title.contentModel
if content_model == "wikitext" then
text = title.text
if title.isSubpage and title.subpageText == "documentation" then
local base_title = title.basePageTitle
if base_title then
title, content_model, text, documentation = base_title, base_title.contentModel, base_title.text, true
end
end
end
-- Content models have overriding priority, as they can appear in
-- nonstandard places due to page content model changes.
if content_model == "css" or content_model == "sanitized-css" then
return get_snippet_subtypes(title, "stylesheet", documentation)
elseif content_model == "javascript" then
return get_snippet_subtypes(title, "script", documentation)
elseif content_model == "json" then
return get_snippet_subtypes(title, "JSON data", documentation)
elseif content_model == "MassMessageListContent" then
return get_snippet_subtypes(title, "mass message delivery list", documentation)
-- Modules.
elseif content_model == "Scribunto" then
return get_transclusion_subtypes(title, "module", documentation, false)
elseif content_model == "text" then
return "page" -- ???
-- Otherwise, the content model is "wikitext", so check namespaces.
elseif title.isTalkPage then
return "talk page"
end
local ns = title.namespace
-- Main namespace.
if ns == 0 then
return "entry"
-- Wiktionary:
elseif ns == 4 then
return find_sandbox(title.text) and "sandbox" or "project page"
-- Template:
elseif ns == 10 then
return get_transclusion_subtypes(title, "template", documentation, false)
end
-- Convert the namespace to lowercase, unless it contains a capital
-- letter after the initial letter (e.g. MediaWiki, TimedText). Also
-- normalize any underscores.
local ns_text = gsub(title.nsText, "_", " ")
if ufind(ns_text, "^%U*$", 2) then
ns_text = ulower(ns_text)
end
-- User:
if ns == 2 then
return ns_text .. " " .. (title.isSubpage and "subpage" or "page")
-- Category: and Appendix:
elseif ns == 14 or ns == 100 then
return ns_text
-- Thesaurus: and Reconstruction:
elseif ns == 110 or ns == 118 then
return ns_text .. " entry"
end
return ns_text .. " page"
end
get_pagetype = export.get_pagetype
end
--[==[
Returns {true} if the input title object is for a content page, or {false} if not. A content page is a page that is considered part of the dictionary itself, and excludes pages for discussion, administration, maintenance etc.]==]
function export.is_content_page(title)
if not is_internal_title(title) then
error(mw.dumpObject(title.fullText) .. " is not a valid page name.")
end
local ns = title.namespace
-- (main), Appendix, Thesaurus, Citations, Reconstruction.
return (ns == 0 or ns == 100 or ns == 110 or ns == 114 or ns == 118) and
title.contentModel == "wikitext"
end
--[==[
Returns {true} if the input title object is for a documentation page, or {false} if not.]==]
function export.is_documentation(title)
return match(get_pagetype(title), "%f[%w]documentation%f[%W]") and true or false
end
--[==[
Returns {true} if the input title object is for a sandbox, or {false} if not.
By default, sandbox documentation pages are excluded, but this can be overridden with the `include_documentation` parameter.]==]
function export.is_sandbox(title, include_documentation)
local pagetype = get_pagetype(title)
return match(pagetype, "%f[%w]sandbox%f[%W]") and (
include_documentation or
not match(pagetype, "%f[%w]documentation%f[%W]")
) and true or false
end
--[==[
Returns {true} if the input title object is for a testcase page, or {false} if not.
By default, testcase documentation pages are excluded, but this can be overridden with the `include_documentation` parameter.]==]
function export.is_testcase_page(title, include_documentation)
local pagetype = get_pagetype(title)
return match(pagetype, "%f[%w]testcase%f[%W]") and (
include_documentation or
not match(pagetype, "%f[%w]documentation%f[%W]")
) and true or false
end
--[==[
Returns the namespace shortcut for the input title object, or else the namespace text. For example, a `Template:` title returns {"T"}, a `Module:` title returns {"MOD"}, and a `User:` title returns {"User"}.]==]
function export.get_namespace_shortcut(title)
return (namespace_shortcuts or get_namespace_shortcuts())[title.namespace] or title.nsText
end
get_namespace_shortcut = export.get_namespace_shortcut
do
local function check_level(lvl)
if type(lvl) ~= "number" then
error("Heading levels must be numbers.")
elseif lvl < 1 or lvl > 6 or lvl % 1 ~= 0 then
error("Heading levels must be integers between 1 and 6.")
end
return lvl
end
--[==[
A helper function which iterates over the headings in `text`, which should be the content of a page or (main) section.
Each iteration returns three values: `sec` (the section title), `lvl` (the section level) and `loc` (the index of the section in the given text, from the first equals sign). The section title will be automatically trimmed, and any HTML entities will be resolved.
The optional parameter `a` (which should be an integer between 1 and 6) can be used to ensure that only headings of the specified level are iterated over. If `b` is also given, then they are treated as a range.
The optional parameters `a` and `b` can be used to specify a range, so that only headings with levels in that range are returned.]==]
local function find_headings(text, a, b)
a = a and check_level(a) or nil
b = b and check_level(b) or a or nil
local start, loc, lvl, sec = 1
return function()
repeat
loc, lvl, sec, start = match(text, "()%f[^%z\n](==?=?=?=?=?)([^\n]+)%2[\t ]*%f[%z\n]()", start)
lvl = lvl and #lvl
until not (sec and a) or (lvl >= a and lvl <= b)
return sec and trim(decode_entities(sec)) or nil, lvl, loc
end
end
local function _get_section(content, name, level)
if not (content and name) then
return nil
elseif find(name, "\n", 1, true) then
error("Heading name cannot contain a newline.")
end
level = level and check_level(level) or nil
name = trim(decode_entities(name))
local start
for sec, lvl, loc in find_headings(content, level and 1 or nil, level) do
if start and lvl <= level then
return sub(content, start, loc - 1)
elseif not start and (not level or lvl == level) and sec == name then
start, level = loc, lvl
end
end
return start and sub(content, start)
end
--[==[
A helper function to return the content of a page section.
`content` is raw wikitext, `name` is the requested section, and `level` is an optional parameter that specifies
the required section heading level. If `level` is not supplied, then the first section called `name` is returned.
`name` can either be a string or table of section names. If a table, each name represents a section that has the
next as a subsection. For example, { {"Spanish", "Noun"}} will return the first matching section called "Noun"
under a section called "Spanish". These do not have to be at adjacent levels ("Noun" might be L4, while "Spanish"
is L2). If `level` is given, it refers to the last name in the table (i.e. the name of the section to be returned).
The returned section includes all of its subsections. If no matching section is found, return {nil}.]==]
function export.get_section(content, names, level)
if type(names) ~= "table" then
return _get_section(content, names, level)
end
local i = 1
local name = names[i]
if not name then
error("Must specify at least 1 section.")
end
while true do
local nxt_i = i + 1
local nxt = names[nxt_i]
if nxt == nil then
return _get_section(content, name, level)
end
content = _get_section(content, name)
if content == nil then
return nil
elseif i == 6 then
error("Not possible specify more than 6 sections: headings only go up to level 6.")
end
i = nxt_i
name = names[i]
end
return content
end
end
do
local current_section
--[==[
A function which returns the number of the page section which contains the current {#invoke}.]==]
function export.get_current_section()
if current_section ~= nil then
return current_section
end
local extension_tag = (current_frame or get_current_frame()).extensionTag
-- We determine the section via the heading strip marker count, since they're numbered sequentially, but the only way to do this is to generate a fake heading via frame:preprocess(). The native parser assigns each heading a unique marker, but frame:preprocess() will return copies of older markers if the heading is identical to one further up the page, so the fake heading has to be unique to the page. The best way to do this is to feed it a heading containing a nowiki marker (which we will need later), since those are always unique.
local nowiki_marker = extension_tag(current_frame, "nowiki")
-- Note: heading strip markers have a different syntax to the ones used for tags.
local h = tonumber(match(
current_frame:preprocess("=" .. nowiki_marker .. "="),
"\127'\"`UNIQ%-%-h%-(%d+)%-%-QINU`\"'\127"
))
-- For some reason, [[Special:ExpandTemplates]] doesn't generate a heading strip marker, so if that happens we simply abort early.
if not h then
return 0
end
-- The only way to get the section number is to increment the heading count, so we store the offset in nowiki strip markers which can be retrieved by procedurally unstripping nowiki markers, counting backwards until we find a match.
local n, offset = tonumber(match(
nowiki_marker,
"\127'\"`UNIQ%-%-nowiki%-([%dA-F]+)%-QINU`\"'\127"
), 16)
while not offset and n > 0 do
n = n - 1
offset = match(
unstrip_nowiki(format("\127'\"`UNIQ--nowiki-%08X-QINU`\"'\127", n)),
"^HEADING\1(%d+)" -- Prefix "HEADING\1" prevents collisions.
)
end
offset = offset and (offset + 1) or 0
extension_tag(current_frame, "nowiki", "HEADING\1" .. offset)
current_section = h - offset
return current_section
end
get_current_section = export.get_current_section
end
do
local L2_sections
local function get_L2_sections()
L2_sections, get_L2_sections = mw.loadData("Module:headword/data").page.L2_sections, nil
return L2_sections
end
--[==[
A function which returns the name of the L2 language section which contains the current {#invoke}.]==]
function export.get_current_L2()
local section = get_current_section()
if section == 0 then
return
end
while section > 0 do
local L2 = (L2_sections or get_L2_sections())[section]
if L2 then
return L2
end
section = section - 1
end
end
end
return export
fahzb5v4u71j961eqb048ciy8nk4h06
218848
218847
2025-06-20T00:57:25Z
Sponge2490
8927
Membatalkan semakan [[Special:Diff/218847|218847]] oleh [[Special:Contributions/Sponge2490|Sponge2490]] ([[User talk:Sponge2490|perbincangan]]) Ralat
218848
Scribunto
text/plain
local require = require
local require_when_needed = require("Module:require when needed")
local decode_entities = require_when_needed("Module:string utilities", "decode_entities")
local find = string.find
local format = string.format
local get_current_section -- Defined below.
local gsub = string.gsub
local is_valid_title -- Defined below.
local lower = string.lower
local match = string.match
local new_title = mw.title.new
local sub = string.sub
local tonumber = tonumber
local trim = require_when_needed("Module:string utilities", "trim")
local type = type
local unstrip_nowiki = mw.text.unstripNoWiki
local export = {}
--[==[
Returns true if the title object is a valid title that is not an interwiki link.]==]
function export.is_valid_title(title)
-- Note: Mainspace titles starting with "#" should be invalid, but a bug in mw.title.new and mw.title.makeTitle means a title object is returned that has the empty string for prefixedText, so they need to be filtered out.
return title and #title.prefixedText > 0 and #title.interwiki == 0
end
is_valid_title = export.is_valid_title
--[==[
Returns true if `pagename` is a valid page title that is not an interwiki link.]==]
function export.is_valid_page_name(pagename)
return is_valid_title(new_title(pagename))
end
do
-- Any template/module with "sandbox" in the title. These are impossible
-- to screen for more accurately, as there's no consistent pattern. Also
-- any user sandboxes in the form (e.g.) "Template:User:...".
local function is_sandbox(text)
return (find(lower(text), "sandbox", 1, true) or sub(text, 1, 5) == "Pengguna:") and true or false
end
-- Any template/module documentation pages.
local function is_documentation(text)
return match(text, "./doc$") and true or false
end
-- Any template/module testcases (which can be labelled and/or followed by
-- further subpages).
local function is_testcase_page(text)
return match(text, "./[Tt]estcases?%f[%L]") and true or false
end
--[==[
Returns the page type of `title` in a format which can be used in running text.]==]
function export.pagetype(title)
if not is_valid_title(title) then
error(mw.dumpObject(title.fullText) .. " is not a valid page name.")
end
-- Content models have overriding priority, as they can appear in
-- nonstandard places due to page content model changes.
local content_model = title.contentModel
if content_model == "css" or content_model == "sanitized-css" then
return "stylesheet"
elseif content_model == "javascript" then
return "script"
elseif content_model == "json" then
return "JSON data page"
elseif content_model == "MassMessageListContent" then
return "mass message delivery list"
-- Modules.
elseif content_model == "Scribunto" then
local title_text = title.text
if is_sandbox(title_text) then
return "module sandbox"
elseif is_testcase_page(title_text) then
return "module testcase page"
end
return "module"
elseif content_model == "text" then
return "page" -- ???
-- Otherwise, the content model is "wikitext", so check namespaces.
elseif title.isTalkPage then
return "talk page"
end
local ns = title.namespace
-- Main namespace.
if ns == 0 then
return "entry"
-- Wiktionary:
elseif ns == 4 then
return "project page"
-- MediaWiki: and TimedText:
elseif ns == 8 or ns == 710 then
return title.nsText .. " page"
elseif ns == 10 then
local title_text = title.text
if is_sandbox(title_text) then
return "template sandbox"
elseif is_documentation(title_text) then
return "template documentation page"
elseif is_testcase_page(title_text) then
return "template testcase page"
end
return "template"
-- Any non-Scribunto pages in the Module: space (which will almost
-- always be documentation subpages). Any remaining will get default
-- handling as "module pages".
elseif ns == 828 then
local title_text = title.text
if is_sandbox(title_text) then
return "module sandbox"
elseif is_documentation(title_text) then
return "module documentation page"
end
end
local ns_text = lower(title.nsText)
-- Category: and Appendix:
if ns == 14 or ns == 100 then
return ns_text
-- Thesaurus: and Reconstruction:
elseif ns == 110 or ns == 118 then
return ns_text .. " entry"
end
return gsub(ns_text, "_", " ") .. " page"
end
end
do
local function check_level(lvl)
if type(lvl) ~= "number" then
error("Heading levels must be numbers.")
elseif lvl < 1 or lvl > 6 or lvl % 1 ~= 0 then
error("Heading levels must be integers between 1 and 6.")
end
return lvl
end
--[==[
A helper function which iterates over the headings in `text`, which should be the content of a page or (main) section.
Each iteration returns three values: `sec` (the section title), `lvl` (the section level) and `loc` (the index of the section in the given text, from the first equals sign). The section title will be automatically trimmed, and any HTML entities will be resolved.
The optional parameter `a` (which should be an integer between 1 and 6) can be used to ensure that only headings of the specified level are iterated over. If `b` is also given, then they are treated as a range.
The optional parameters `a` and `b` can be used to specify a range, so that only headings with levels in that range are returned. If only `a` is given ...
]==]
local function find_headings(text, a, b)
a = a and check_level(a) or nil
b = b and check_level(b) or a or nil
local start, loc, lvl, sec = 1
return function()
repeat
loc, lvl, sec, start = match(text, "()%f[^%z\n](==?=?=?=?=?)([^\n]+)%2[\t ]*%f[%z\n]()", start)
lvl = lvl and #lvl
until not (sec and a) or (lvl >= a and lvl <= b)
return sec and trim(decode_entities(sec)) or nil, lvl, loc
end
end
local function _get_section(content, name, level)
if not (content and name) then
return nil
elseif find(name, "\n", 1, true) then
error("Heading name cannot contain a newline.")
end
level = level and check_level(level) or nil
name = trim(decode_entities(name))
local start
for sec, lvl, loc in find_headings(content, level and 1 or nil, level) do
if start and lvl <= level then
return sub(content, start, loc - 1)
elseif not start and (not level or lvl == level) and sec == name then
start, level = loc, lvl
end
end
return start and sub(content, start)
end
--[==[
A helper function to return the content of a page section.
`content` is raw wikitext, `name` is the requested section, and `level` is an optional parameter that specifies
the required section heading level. If `level` is not supplied, then the first section called `name` is returned.
`name` can either be a string or table of section names. If a table, each name represents a section that has the
next as a subsection. For example, { {"Spanish", "Noun"}} will return the first matching section called "Noun"
under a section called "Spanish". These do not have to be at adjacent levels ("Noun" might be L4, while "Spanish"
is L2). If `level` is given, it refers to the last name in the table (i.e. the name of the section to be returned).
The returned section includes all of its subsections. If no matching section is found, return {nil}.
]==]
function export.get_section(content, names, level)
if type(names) ~= "table" then
return _get_section(content, names, level)
end
local i = 1
local name = names[i]
if not name then
error("Must specify at least 1 section.")
end
while true do
local nxt_i = i + 1
local nxt = names[nxt_i]
if nxt == nil then
return _get_section(content, name, level)
end
content = _get_section(content, name)
if content == nil then
return nil
elseif i == 6 then
error("Not possible specify more than 6 sections: headings only go up to level 6.")
end
i = nxt_i
name = names[i]
end
return content
end
end
do
local current_section
--[==[
A function which returns the number of the page section which contains the current {#invoke}.
]==]
function export.get_current_section()
if current_section then
return current_section
end
local frame = mw.getCurrentFrame()
local extension_tag = frame.extensionTag
-- We determine the section via the heading strip marker count, since they're numbered sequentially, but the only way to do this is to generate a fake heading via frame:preprocess(). The native parser assigns each heading a unique marker, but frame:preprocess() will return copies of older markers if the heading is identical to one further up the page, so the fake heading has to be unique to the page. The best way to do this is to feed it a heading containing a nowiki marker (which we will need later), since those are always unique.
local nowiki_marker = extension_tag(frame, "nowiki")
-- Note: heading strip markers have a different syntax to the ones used for tags.
local h = tonumber(match(
frame:preprocess("=" .. nowiki_marker .. "="),
"\127'\"`UNIQ%-%-h%-(%d+)%-%-QINU`\"'\127"
))
-- For some reason, [[Special:ExpandTemplates]] doesn't generate a heading strip marker, so if that happens we simply abort early.
if not h then
return 0
end
-- The only way to get the section number is to increment the heading count, so we store the offset in nowiki strip markers which can be retrieved by procedurally unstripping nowiki markers, counting backwards until we find a match.
local n, offset = tonumber(match(
nowiki_marker,
"\127'\"`UNIQ%-%-nowiki%-([%dA-F]+)%-QINU`\"'\127"
), 16)
while not offset and n > 0 do
n = n - 1
offset = match(
unstrip_nowiki(format("\127'\"`UNIQ--nowiki-%08X-QINU`\"'\127", n)),
"^HEADING\1(%d+)" -- Prefix "HEADING\1" prevents collisions.
)
end
offset = offset and (offset + 1) or 0
extension_tag(frame, "nowiki", "HEADING\1" .. offset)
current_section = h - offset
return current_section
end
get_current_section = export.get_current_section
end
do
local L2_sections
--[==[
A function which returns the name of the L2 language section which contains the current {#invoke}.
]==]
function export.get_current_L2()
local section = get_current_section()
if section == 0 then
return
end
L2_sections = L2_sections or mw.loadData("Module:headword/data").page.L2_sections
while section > 0 do
local L2 = L2_sections[section]
if L2 then
return L2
end
section = section - 1
end
end
end
return export
acr7fss28efekbh2ifbr49y2erogs5u
Modul:string/patternEscape
828
75062
218838
2025-06-19T23:30:10Z
Sponge2490
8927
Mencipta [[Modul:string/patternEscape]]
218838
Scribunto
text/plain
local gsub = string.gsub
local chars
local function get_chars()
chars, get_chars = {
["\000"] = "%z", ["$"] = "%$", ["%"] = "%%", ["("] = "%(", [")"] = "%)",
["*"] = "%*", ["+"] = "%+", ["-"] = "%-", ["."] = "%.", ["?"] = "%?",
["["] = "%[", ["]"] = "%]", ["^"] = "%^",
}, nil
return chars
end
--[==[Escapes the magic characters used in a pattern: {$%()*+-.?[]^}, and converts the null character to {%z}. For example, {"^$()%.[]*+-?\0"} becomes {"%^%$%(%)%%%.%[%]%*%+%-%?%z"}. This is necessary when constructing a pattern involving arbitrary text (e.g. from user input).]==]
return function(str)
return (gsub(str, "[%z$%%()*+%-.?[%]^]", chars or get_chars()))
end
kdhwp5dohwvh931huz7m0oufqqh05wl
Modul:string/replacementEscape
828
75063
218839
2025-06-19T23:35:02Z
Sponge2490
8927
Mencipta [[Modul:string/replacementEscape]]
218839
Scribunto
text/plain
local gsub = string.gsub
--[==[Escapes {%}, which is the only magic character used in replacement strings, which are given as the third argument to {string.gsub} and {mw.ustring.gsub}, as well as format strings given to {string.format} and {mw.ustring.format}.]==]
return function(str)
return (gsub(str, "%%", "%%%%"))
end
aid90he3azqkc4qrytnczmfsjczbfe3
Modul:table/deepCopy
828
75064
218841
2025-06-19T23:44:11Z
Sponge2490
8927
Mencipta [[Modul:table/deepCopy]]
218841
Scribunto
text/plain
local debug_track_module = "Module:debug/track"
local dump = mw.dumpObject
local error = error
local getmetatable = getmetatable
local next = next
local pairs = pairs
local rawget = rawget
local type = type
local setmetatable = setmetatable
local function debug_track(...)
debug_track = require(debug_track_module)
return debug_track(...)
end
local tracked
local function make_copy(orig, seen, mt_flag, keep_loaded_data)
local mt, iter, state, init = getmetatable(orig)
-- If `mt` is nil, just use `next`, as it's faster.
if mt == nil then
iter, state, init = next, orig, nil
-- `mt` could be a non-table if `__metatable` has been used, but discard it in such cases.
elseif type(mt) ~= "table" then
mt, iter, state, init = nil, pairs(orig)
-- Data loaded via `mw.loadData`, which sets the key "mw_loadData" to true in the metatable.
elseif rawget(mt, "mw_loadData") == true then
if keep_loaded_data then
seen[orig] = orig
return orig
-- Track instances of such data being copied, which is very inefficient and usually unnecessary.
elseif not tracked then
debug_track("table/deepCopy/loaded data")
tracked = true
end
-- Discard the metatable and use the `__pairs` metamethod.
mt, iter, state, init = nil, pairs(orig)
-- If `mt_flag` is "none", discard the metatable and use the `__pairs` metamethod.
elseif mt_flag == "none" then
mt, iter, state, init = nil, pairs(orig)
-- Otherwise, keep `mt` and use `next` to copy the raw contents.
else
iter, state, init = next, orig, nil
end
local copy = {}
seen[orig] = copy
for k, v in iter, state, init do
if k and type(k) == "table" then
k = seen[k] or make_copy(k, seen, mt_flag, keep_loaded_data)
end
if v and type(v) == "table" then
v = seen[v] or make_copy(v, seen, mt_flag, keep_loaded_data)
end
copy[k] = v
end
if mt == nil or mt_flag == "none" then
return copy
-- Copy the metatable if `mt_flag` is "copy"; otherwise, it will be "keep", so keep it.
elseif mt_flag == "copy" then
mt = seen[mt] or make_copy(mt, seen, mt_flag, keep_loaded_data)
end
return setmetatable(copy, mt)
end
--[==[
Recursive deep copy function. Preserves copied identities of subtables.
A more powerful version of {mw.clone}, with customizable options.
* `metatableFlag` can be one of three options:
*# "none" (the default): `pairs` will be used to copy the table, meaning that any `__pairs` metamethod will be used to copy the table, if available; the resulting table will not have a metatable.
*# "copy": a raw copy of the table will be made (i.e. any `__pairs` metamethod will be ignored), and the copy will be given a copy of the original table's metatable; this ensures that nothing from the original is retained, but may cause metamethods to behave unexpectedly, depending on their implementation.
*# "keep": a raw copy of the table will be made (i.e. any `__pairs` metamethod will be ignored), and the copy will be given the original table's metatable; this is useful when copying objects that inherit methods from a prototype object (e.g. language objects).
* If `keepLoadedData` is true, then any data loaded via {mw.loadData} will not be copied, and the original will be used instead. This is useful in iterative contexts where it is necessary to copy data being destructively modified, because objects loaded via mw.loadData are immutable.
* Notes:
*# Protected metatables will not be copied (i.e. those hidden behind a `__metatable` metamethod), as they are not accessible by Lua's design. Instead, the output of the `__metatable` method will be used instead.
*# Data loaded via {mw.loadData} is always treated as though the "none" flag is set, because the way it has been implemented causes errors to be thrown if "copy" or "keep" are used with it.]==]
return function(orig, metatableFlag, keepLoadedData)
if metatableFlag == nil then
metatableFlag = "none"
elseif not (metatableFlag == "keep" or metatableFlag == "copy" or metatableFlag == "none") then
error('metatableFlag must be "none", "copy", "keep" or nil; received ' .. dump(metatableFlag))
end
if orig and type(orig) == "table" then
return make_copy(orig, {}, metatableFlag, keepLoadedData)
end
return orig
end
n283xd4cxzrnpyf4zrlt9334gjwqw59
Modul:table/getNested
828
75065
218842
2025-06-19T23:48:51Z
Sponge2490
8927
Mencipta [[Modul:table/getNested]]
218842
Scribunto
text/plain
local error = error
local select = select
--[==[
Given a table and an arbitrary number of keys, will successively access subtables using each key in turn, returning the value at the final key. For example, if {t} is { {[1] = {[2] = {[3] = "foo"}}}}, {export.getNested(t, 1, 2, 3)} will return {"foo"}.
If no subtable exists for a given key value, returns nil, but will throw an error if a non-table is found at an intermediary key.]==]
return function(...)
local n = select("#", ...)
if n < 2 then
error("Must provide a table and at least one key.")
end
local t, k = ...
for i = 3, n do
local v = t[k]
if v == nil then
return nil
end
t, k = v, select(i, ...)
end
return t[k]
end
tm1q0pycz7xr0ute9n4h4yhpf1jzo33
Modul:table/setNested
828
75066
218843
2025-06-19T23:50:58Z
Sponge2490
8927
Mencipta [[Modul:table/setNested]]
218843
Scribunto
text/plain
local error = error
local select = select
--[==[
Given a table, value and an arbitrary number of keys, will successively access subtables using each key in turn, and sets the value at the final key. For example, if {t} is { {} }, {export.setNested(t, "foo", 1, 2, 3)} will modify {t} to { {[1] = {[2] = {[3] = "foo"} } } }.
If no subtable exists for a given key value, one will be created, but the function will throw an error if a non-table value is found at an intermediary key.
Note: the parameter order (table, value, keys) differs from functions like rawset, because the number of keys can be arbitrary. This is to avoid situations where an additional argument must be appended to arbitrary lists of variables, which can be awkward and error-prone: for example, when handling variable arguments ({...}) or function return values.]==]
return function(...)
local n = select("#", ...)
if n < 3 then
error("Must provide a table, value and at least one key.")
end
local t, v, k = ...
for i = 4, n do
local next_t = t[k]
if next_t == nil then
-- If there's no next table while setting nil, there's nothing more
-- to do.
if v == nil then
return
end
next_t = {}
t[k] = next_t
end
t, k = next_t, select(i, ...)
end
t[k] = v
end
1jxfjipchypy8qfjkmtb9b9sal1bcc1
muddal
0
75067
218849
2025-06-20T03:21:03Z
180.195.212.239
Mencipta laman baru dengan kandungan '==Bahasa Suluk== ===Takrifan=== ====Kata nama==== {{inti|tsg|kata nama}} # [[modal]] #: {{syn|tsg|puun}} ===Etimologi=== {{bor+|tsg|ms|modal}}, daripada {{der|tsg|ta|முதல்}}.'
218849
wikitext
text/x-wiki
==Bahasa Suluk==
===Takrifan===
====Kata nama====
{{inti|tsg|kata nama}}
# [[modal]]
#: {{syn|tsg|puun}}
===Etimologi===
{{bor+|tsg|ms|modal}}, daripada {{der|tsg|ta|முதல்}}.
888ygqfk02x9tnp5h9s3d5jq9q29aht