Skip to content

Commit 1850184

Browse files
committed
Add simple codepoint redirections to unaccent.rules.
Previously we searched for code points where the Unicode data file listed an equivalent combining character sequence that added accents. Some codepoints redirect to a single other codepoint, instead of doing any combining. We can follow those references recursively to get the answer. Per bug report #18362, which reported missing Ancient Greek characters. Specifically, precomposed characters with oxia (from the polytonic accent system used for old Greek) just point to precomposed characters with tonos (from the monotonic accent system for modern Greek), and we have to follow the extra hop to find out that they are composed with an acute accent. Besides those, the new rule also: * pulls in a lot of 'Mathematical Alphanumeric Symbols', which are copies of the Latin and Greek alphabets and numbers rendered in different typefaces, and * corrects a single mathematical letter that previously came from the CLDR transliteration file, but the new rule extracts from the main Unicode database file, where clearly the latter is right and the former is a wrong (reported to CLDR). Reported-by: Cees van Zeeland <cees.van.zeeland@freedom.nl> Reviewed-by: Robert Haas <robertmhaas@gmail.com> Reviewed-by: Peter Eisentraut <peter@eisentraut.org> Reviewed-by: Michael Paquier <michael@paquier.xyz> Discussion: https://postgr.es/m/18362-be6d0cfe122b6354%40postgresql.org
1 parent 1eff827 commit 1850184

File tree

3 files changed

+1025
-9
lines changed

3 files changed

+1025
-9
lines changed

contrib/unaccent/expected/unaccent.out

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -176,6 +176,6 @@ SELECT ts_lexize('unaccent', '〝');
176176
SELECT unaccent('ℌ');
177177
unaccent
178178
----------
179-
x
179+
H
180180
(1 row)
181181

contrib/unaccent/generate_unaccent_rules.py

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -104,10 +104,11 @@ def is_letter_with_marks(codepoint, table):
104104
"""Returns true for letters combined with one or more marks."""
105105
# See https://www.unicode.org/reports/tr44/tr44-14.html#General_Category_Values
106106

107-
# Letter may have no combining characters, in which case it has
108-
# no marks.
109-
if len(codepoint.combining_ids) == 1:
110-
return False
107+
# Some codepoints redirect directly to another, instead of doing any
108+
# "combining"... but sometimes they redirect to a codepoint that doesn't
109+
# exist, so ignore those.
110+
if len(codepoint.combining_ids) == 1 and codepoint.combining_ids[0] in table:
111+
return is_letter_with_marks(table[codepoint.combining_ids[0]], table)
111112

112113
# A letter without diacritical marks has none of them.
113114
if any(is_mark(table[i]) for i in codepoint.combining_ids[1:]) is False:
@@ -148,8 +149,7 @@ def get_plain_letter(codepoint, table):
148149

149150
def is_ligature(codepoint, table):
150151
"""Return true for letters combined with letters."""
151-
return all(is_letter(table[i], table) for i in codepoint.combining_ids)
152-
152+
return all(i in table and is_letter(table[i], table) for i in codepoint.combining_ids)
153153

154154
def get_plain_letters(codepoint, table):
155155
"""Return a list of plain letters from a ligature."""
@@ -200,6 +200,11 @@ def parse_cldr_latin_ascii_transliterator(latinAsciiFilePath):
200200
# the parser of unaccent only accepts non-whitespace characters
201201
# for "src" and "trg" (see unaccent.c)
202202
if not src.isspace() and not trg.isspace():
203+
if src == "\u210c":
204+
# This mapping seems to be in error, and causes a collision
205+
# by disagreeing with the main Unicode database file:
206+
# https://unicode-org.atlassian.net/browse/CLDR-17656
207+
continue
203208
charactersSet.add((ord(src), trg))
204209

205210
return charactersSet
@@ -251,7 +256,7 @@ def main(args):
251256
# walk through all the codepoints looking for interesting mappings
252257
for codepoint in all:
253258
if codepoint.general_category.startswith('L') and \
254-
len(codepoint.combining_ids) > 1:
259+
len(codepoint.combining_ids) > 0:
255260
if is_letter_with_marks(codepoint, table):
256261
charactersSet.add((codepoint.id,
257262
chr(get_plain_letter(codepoint, table).id)))

0 commit comments

Comments
 (0)