<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
	<id>https://linguifex.com/w/index.php?action=history&amp;feed=atom&amp;title=Module%3AHani</id>
	<title>Module:Hani - Revision history</title>
	<link rel="self" type="application/atom+xml" href="https://linguifex.com/w/index.php?action=history&amp;feed=atom&amp;title=Module%3AHani"/>
	<link rel="alternate" type="text/html" href="https://linguifex.com/w/index.php?title=Module:Hani&amp;action=history"/>
	<updated>2026-04-22T22:27:07Z</updated>
	<subtitle>Revision history for this page on the wiki</subtitle>
	<generator>MediaWiki 1.43.6</generator>
	<entry>
		<id>https://linguifex.com/w/index.php?title=Module:Hani&amp;diff=495339&amp;oldid=prev</id>
		<title>Sware: 1 revision imported</title>
		<link rel="alternate" type="text/html" href="https://linguifex.com/w/index.php?title=Module:Hani&amp;diff=495339&amp;oldid=prev"/>
		<updated>2026-04-21T12:00:56Z</updated>

		<summary type="html">&lt;p&gt;1 revision imported&lt;/p&gt;
&lt;table style=&quot;background-color: #fff; color: #202122;&quot; data-mw=&quot;interface&quot;&gt;
				&lt;tr class=&quot;diff-title&quot; lang=&quot;en&quot;&gt;
				&lt;td colspan=&quot;1&quot; style=&quot;background-color: #fff; color: #202122; text-align: center;&quot;&gt;← Older revision&lt;/td&gt;
				&lt;td colspan=&quot;1&quot; style=&quot;background-color: #fff; color: #202122; text-align: center;&quot;&gt;Revision as of 12:00, 21 April 2026&lt;/td&gt;
				&lt;/tr&gt;&lt;tr&gt;&lt;td colspan=&quot;2&quot; class=&quot;diff-notice&quot; lang=&quot;en&quot;&gt;&lt;div class=&quot;mw-diff-empty&quot;&gt;(No difference)&lt;/div&gt;
&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;</summary>
		<author><name>Sware</name></author>
	</entry>
	<entry>
		<id>https://linguifex.com/w/index.php?title=Module:Hani&amp;diff=495338&amp;oldid=prev</id>
		<title>wikt&gt;Theknightwho: Track and log bad IDS sequences which occur with `fallback`.</title>
		<link rel="alternate" type="text/html" href="https://linguifex.com/w/index.php?title=Module:Hani&amp;diff=495338&amp;oldid=prev"/>
		<updated>2024-07-20T19:13:40Z</updated>

		<summary type="html">&lt;p&gt;Track and log bad IDS sequences which occur with `fallback`.&lt;/p&gt;
&lt;p&gt;&lt;b&gt;New page&lt;/b&gt;&lt;/p&gt;&lt;div&gt;local concat = table.concat&lt;br /&gt;
local explode = require(&amp;quot;Module:string utilities&amp;quot;).explode_utf8&lt;br /&gt;
local find = string.find&lt;br /&gt;
local insert = table.insert&lt;br /&gt;
local match = string.match&lt;br /&gt;
local pcall = pcall&lt;br /&gt;
local umatch = mw.ustring.match&lt;br /&gt;
&lt;br /&gt;
local export = {}&lt;br /&gt;
&lt;br /&gt;
do&lt;br /&gt;
	local ids = mw.loadData(&amp;quot;Module:Hani/data&amp;quot;).ids&lt;br /&gt;
	&lt;br /&gt;
	local function find_end_of_ids(text, i, components)&lt;br /&gt;
		local component, j, success = 0, i&lt;br /&gt;
		repeat&lt;br /&gt;
			component = component + 1&lt;br /&gt;
			j = j + 1&lt;br /&gt;
			local char = text[j]&lt;br /&gt;
			-- If it&amp;#039;s the end of the string or a space, fail the whole sequence and backtrack.&lt;br /&gt;
			if not char or umatch(char, &amp;quot;%s&amp;quot;) then&lt;br /&gt;
				-- Throw an error object containing the end index and the expected number of remaining characters.&lt;br /&gt;
				error{_end = j - 1, _expected = components - component + 1}&lt;br /&gt;
			end&lt;br /&gt;
			local new_components = ids[char]&lt;br /&gt;
			if new_components then&lt;br /&gt;
				success, j = pcall(find_end_of_ids, text, j, new_components)&lt;br /&gt;
				if not success then&lt;br /&gt;
					-- Add any additional expected characters.&lt;br /&gt;
					if j._expected then&lt;br /&gt;
						j._expected = j._expected + components - component&lt;br /&gt;
					end&lt;br /&gt;
					error(j)&lt;br /&gt;
				end&lt;br /&gt;
			end&lt;br /&gt;
		until component == components&lt;br /&gt;
		return j&lt;br /&gt;
	end&lt;br /&gt;
	&lt;br /&gt;
	-- Explodes a string of characters into an array, taking into account any ideographic description characters (IDS). By default, it throws an error if invalid IDS is found. If `fallback` is set, the invalid sequence is split into the largest possible components (e.g. &amp;quot;⿲⿸AB⿱CD&amp;quot; would be split into &amp;quot;⿲&amp;quot;, &amp;quot;⿸AB&amp;quot; and &amp;quot;⿱CD&amp;quot;, while &amp;quot;⿰⿱AB⿰C&amp;quot; would be split into &amp;quot;⿰&amp;quot;, &amp;quot;⿱AB&amp;quot;, &amp;quot;⿰&amp;quot; and &amp;quot;C&amp;quot;); this is useful for sortkey contexts, as invalid sequences may occur in arbitrary input.&lt;br /&gt;
	function export.explode_chars(text, fallback)&lt;br /&gt;
		if not (match(text, &amp;quot;\226\191[\176-\191]&amp;quot;) or find(text, &amp;quot;〾&amp;quot;) or find(text, &amp;quot;㇯&amp;quot;)) then&lt;br /&gt;
			return explode(text)&lt;br /&gt;
		end&lt;br /&gt;
		text = explode(text)&lt;br /&gt;
		local ret, text_len, i = {}, #text, 0&lt;br /&gt;
		repeat&lt;br /&gt;
			i = i + 1&lt;br /&gt;
			local char = text[i]&lt;br /&gt;
			local components = ids[char]&lt;br /&gt;
			if components then&lt;br /&gt;
				local success, j = pcall(find_end_of_ids, text, i, components)&lt;br /&gt;
				if success then&lt;br /&gt;
					char = concat(text, nil, i, j)&lt;br /&gt;
					i = j&lt;br /&gt;
				elseif not j._expected then -- Any other errors (e.g. stack overflows) will be strings.&lt;br /&gt;
					error(j)&lt;br /&gt;
				else&lt;br /&gt;
					j = &amp;quot;Invalid IDS sequence: \&amp;quot;&amp;quot; .. concat(text, nil, i, j._end) ..&lt;br /&gt;
						&amp;quot;\&amp;quot;: expected &amp;quot; .. j._expected .. &amp;quot; additional character&amp;quot; ..&lt;br /&gt;
						(j._expected == 1 and &amp;quot;&amp;quot; or &amp;quot;s&amp;quot;) .. &amp;quot;.&amp;quot;&lt;br /&gt;
					if not fallback then&lt;br /&gt;
						error(j)&lt;br /&gt;
					end&lt;br /&gt;
					mw.log(j)&lt;br /&gt;
					require(&amp;quot;Module:debug/track&amp;quot;)(&amp;quot;Hani/invalid ids&amp;quot;)&lt;br /&gt;
				end&lt;br /&gt;
			end&lt;br /&gt;
			insert(ret, char)&lt;br /&gt;
		until i == text_len&lt;br /&gt;
		return ret&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
-- Converts any iteration marks (々 and 〻) into the relevant characters in the text, where n repeated iteration marks repeats n previous characters (e.g. &amp;quot;時々&amp;quot; = &amp;quot;時時&amp;quot;, &amp;quot;馬鹿々々しい&amp;quot; = &amp;quot;馬鹿馬鹿しい&amp;quot; etc). Punctuation and unconnected sets of iteraton marks block iteration, with excess marks being left as-is. For example, &amp;quot;X,Y々々&amp;quot; = &amp;quot;X,YY々&amp;quot;, and &amp;quot;X々Y々々&amp;quot; = &amp;quot;XXYY々&amp;quot; (not &amp;quot;XXYXY&amp;quot;).&lt;br /&gt;
function export.convert_iteration_marks(text)&lt;br /&gt;
	if not match(text, &amp;quot;\227\128[\133\187]&amp;quot;) then&lt;br /&gt;
		return text&lt;br /&gt;
	end&lt;br /&gt;
	text = explode(text)&lt;br /&gt;
	-- Work backwards, since sets of iteration marks must be isolated from each other (e.g. &amp;quot;X々Y々々&amp;quot; should be &amp;quot;XXYY々&amp;quot;, with one excess at the end, not &amp;quot;XXYXY&amp;quot;).&lt;br /&gt;
	local i, n = #text, 0&lt;br /&gt;
	while i &amp;gt; 0 do&lt;br /&gt;
		local char = text[i]&lt;br /&gt;
		if char == &amp;quot;々&amp;quot; or char == &amp;quot;〻&amp;quot; then&lt;br /&gt;
			n = n + 1&lt;br /&gt;
		elseif n &amp;gt; 0 then&lt;br /&gt;
			-- Count backwards once for each iteration mark, but stop early if we find something which can&amp;#039;t be iterated, as that marks the start of the set to be repeated.&lt;br /&gt;
			local anchor = i&lt;br /&gt;
			for j = 0, n - 1 do&lt;br /&gt;
				local prev = text[anchor - j]&lt;br /&gt;
				if not prev or prev == &amp;quot;々&amp;quot; or prev == &amp;quot;〻&amp;quot; or umatch(prev, &amp;quot;%W&amp;quot;) then&lt;br /&gt;
					n = j&lt;br /&gt;
					break&lt;br /&gt;
				end&lt;br /&gt;
			end&lt;br /&gt;
			if n &amp;gt; 0 then&lt;br /&gt;
				i = i - n + 1&lt;br /&gt;
				-- Replace iteration marks ahead with the relevant character.&lt;br /&gt;
				for j = i, i + n - 1 do&lt;br /&gt;
					text[j + n] = text[j]&lt;br /&gt;
				end&lt;br /&gt;
				n = 0&lt;br /&gt;
			end&lt;br /&gt;
		end&lt;br /&gt;
		i = i - 1&lt;br /&gt;
	end&lt;br /&gt;
	return concat(text)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
return export&lt;/div&gt;</summary>
		<author><name>wikt&gt;Theknightwho</name></author>
	</entry>
</feed>