Найдите непрерывный диапазон в списке кодовых точек юникода

#unicode #codepoint #unicode-range

Вопрос:

У меня есть список кодовых точек юникода, что-то в этом роде (не фактический набор, только иллюстрация проблемы).:

 uni050B
uni050C
uni050D
uni050E
uni050F
uni0510
uni0511
uni0512
uni0513
uni1E00
uni1E01
uni1E3E
uni1E3F
uni1E80
uni1E81
uni1E82
uni1E83
uni1E84
uni1E85
uni1EA0
and so forth…
 

Мне нужно найти unicode-range для этого. Некоторые части этого набора непрерывны, некоторые точки отсутствуют — так что диапазон не U 050B-1EA0 является .
Существует ли разумный способ извлечения этих непрерывных «поддиапазонов»?

Комментарии:

1. Я не уверен, что вы делаете, но, возможно, вы работаете не с кодовыми точками Юникода , а с символами (так что с обычными сложностями). В таком случае могут помочь библиотеки и инструменты для обработки шрифтов. Дополнительное примечание: ваш вопрос не совсем ясен: о чем вы спрашиваете? Общий алгоритм тривиален, но, возможно, вы ищете конкретный язык и библиотеку? В таком случае полезно включить соответствующий языковой тег, о котором идет речь.

Ответ №1:

Я не знаю ничего «готового», но достаточно простого для расчета. Ниже находит последовательные числа и строит с unicode-range помощью Python:

 import re

def build_range(uni):
    '''Pass a list of sorted positive integers to include in the unicode-range.
    '''
    uni.append(-1) # sentinel prevents having to special case the last element
    start,uni = uni[0],uni[1:]
    current = start

    strings = []
    for u in uni:
        if u == current: # in case of duplicates
            continue
        if u == current   1: # in a consecutive range...
            current = u
        elif start == current: # single element
            strings.append(f'U {current:X}')
            start = current = u
        else: # range
            strings.append(f'U {start:X}-{current:X}')
            start = current = u
        
    return 'unicode-range: '   ', '.join(strings)   ';'

data = '''
uni050B
uni050C
uni050D
uni050E
uni050F
uni0510
uni0511
uni0512
uni0513
uni1E00
uni1E01
uni1E3E
uni1E3F
uni1E80
uni1E81
uni1E82
uni1E83
uni1E84
uni1E85
uni1EA0'''

# parse out the hexadecimal values into an integer list
uni = sorted([int(x,16) for x in re.findall(r'uni([0-9A-F]{4})',data)])

print(build_range(uni))
 

Выход:

 unicode-range: U 50B-513, U 1E00-1E01, U 1E3E-1E3F, U 1E80-1E85, U 1EA0;