2009-09-25 4 views
18

Я хотел бы протестировать обработку Юникода моего кода. Есть ли что-нибудь, что я могу поставить в random.choice() для выбора из всего диапазона Unicode, желательно не внешнего модуля? Кажется, что у Google и StackOverflow нет ответа.Создать произвольную строку UTF-8 в Python

Редактировать: похоже, это сложнее, чем ожидалось, поэтому я перефразирую вопрос. Является ли следующий код достаточным для создания всех допустимых non-control characters in Unicode?

unicode_glyphs = ''.join(
    unichr(char) 
    for char in xrange(1114112) # 0x10ffff + 1 
    if unicodedata.category(unichr(char))[0] in ('LMNPSZ') 
    ) 
+0

Это может помочь, если вы хотите дать более подробную информацию о «проверке обработки Юникодом моего кода» и объясните, какая часть, которая генерирует случайные строки UTF-8, должна играть в этом тестировании и что вы считаете «весь диапазон Unicode» (16 бит? 21 бит? не суррогатные коды? допустимые символы (например, не U + FFFF)?). Вы доверяете кодеку Python UTF-8, или вам нужно также проверить это? Python 2.X или 3.X или оба? –

+1

Цель состоит в том, чтобы принять любые допустимые коды кода (символы) для кода Unicode для ввода для веб-интерфейса в Python 2.6. – l0b0

ответ

7

UTF-8 stress test from Markus Kuhn Вы могли бы использовать.

См. Также Really Good, Bad UTF-8 example test data.

+0

Было бы полезно убедиться, что программа не сломается при получении неверного текста, но это не помогло бы в качестве теста на соответствие. – voyager

+0

+1. l0b0: не беспокойтесь о генерации случайного юникода. Заимствование чужого колеса> изобретает его. –

+3

Хороший ответ, но на самом деле не отвечает на заданный вопрос. – Kylotan

0

Поскольку Unicode является только диапазон - а - кодов, что об использовании unichr(), чтобы получить строку Юникода, соответствующее случайное число между 0 и 0xFFFF?
(Конечно, это даст только один код, так что итерация по мере необходимости)

+3

К сожалению, все не так просто. Unicode содержит намного больше, чем 0x100000 символов, и диапазон не подключен. Например, суррогатные значения никогда не должны отображаться как единые кодовые точки. Таким образом, вопрос о том, что представляет собой действительную строку UTF-8, является весьма нетривиальным. Подробности описаны в определении D92 главы 3 стандарта Unicode. Существует также таблица (3-7)), в которой перечислены все допустимые возможности для последовательностей байтов UTF-8. – Philipp

+0

Я вижу, спасибо :) – Joril

+0

Unicode работает от U + 0000 до U + 10FFFF; есть также многочисленные недопустимые коды, включая (как это бывает) U + FFFF. В стандарте Unicode сказано «<не символ» - значение FFFF гарантировано не является символом Unicode вообще ». –

0

Вы можете загрузить сайт, написанный на греческом или немецком языке, который использует юникод и передает его вашему коду.

3

Это зависит от того, насколько тщательно вы хотите провести тестирование и как точно вы хотите генерировать. Вполне, Unicode - это 21-битный код (U + 0000 .. U + 10FFFF). Тем не менее, некоторые довольно большие куски этого диапазона отложены для пользовательских персонажей. Вы хотите беспокоиться о генерации комбинирования символов в начале строки (потому что они должны появляться только после другого символа)?

Базовый подход, который я бы принял, случайным образом генерирует код кода Unicode (например, U + 2397 или U + 31232), проверяет его в контексте (является ли он законным символом, может ли он отображаться здесь в строке) и кодировать действительные кодовые точки в UTF-8.

Если вы просто хотите проверить, правильно ли ваш код обрабатывает неверные UTF-8, вы можете использовать гораздо более простые схемы генерации.

Обратите внимание, что вам нужно знать, чего ожидать от ввода данных - в противном случае вы не тестируете; вы экспериментируете.

7

Ниже приведен пример функции, которая, вероятно, создает случайный хорошо сформированную последовательность UTF-8, как определено в Таблице 3-7 Юникода 5.0.0:

#!/usr/bin/env python3.1 

# From Table 3–7 of the Unicode Standard 5.0.0 

import random 

def byte_range(first, last): 
    return list(range(first, last+1)) 

first_values = byte_range(0x00, 0x7F) + byte_range(0xC2, 0xF4) 
trailing_values = byte_range(0x80, 0xBF) 

def random_utf8_seq(): 
    first = random.choice(first_values) 
    if first <= 0x7F: 
     return bytes([first]) 
    elif first <= 0xDF: 
     return bytes([first, random.choice(trailing_values)]) 
    elif first == 0xE0: 
     return bytes([first, random.choice(byte_range(0xA0, 0xBF)), random.choice(trailing_values)]) 
    elif first == 0xED: 
     return bytes([first, random.choice(byte_range(0x80, 0x9F)), random.choice(trailing_values)]) 
    elif first <= 0xEF: 
     return bytes([first, random.choice(trailing_values), random.choice(trailing_values)]) 
    elif first == 0xF0: 
     return bytes([first, random.choice(byte_range(0x90, 0xBF)), random.choice(trailing_values), random.choice(trailing_values)]) 
    elif first <= 0xF3: 
     return bytes([first, random.choice(trailing_values), random.choice(trailing_values), random.choice(trailing_values)]) 
    elif first == 0xF4: 
     return bytes([first, random.choice(byte_range(0x80, 0x8F)), random.choice(trailing_values), random.choice(trailing_values)]) 

print("".join(str(random_utf8_seq(), "utf8") for i in range(10))) 

Из-за обширности стандарта Unicode Я не могу проверить это полностью. Также обратите внимание, что символы неравномерно распределены (но каждый байт в последовательности).

0

Отвечая пересмотренную вопрос:

Да, на строгом определении «управляющие символы» - обратите внимание, что вы не будете включать CR, LF и TAB; Это то что ты хочешь?

Пожалуйста, подумайте о том, чтобы ответить на мое раннее приглашение, чтобы сообщить нам, что вы на самом деле пытаетесь сделать.

10

Люди могут найти свой путь здесь, основываясь главным образом на заголовке вопроса, поэтому вот способ создания случайной строки, содержащей множество символов Юникода. Чтобы включить больше (или меньше) возможных символов, просто расширьте эту часть примера с помощью диапазонов кодовых точек, которые вы хотите.

import random 

def get_random_unicode(length): 

    try: 
     get_char = unichr 
    except NameError: 
     get_char = chr 

    # Update this to include code point ranges to be sampled 
    include_ranges = [ 
     (0x0021, 0x0021), 
     (0x0023, 0x0026), 
     (0x0028, 0x007E), 
     (0x00A1, 0x00AC), 
     (0x00AE, 0x00FF), 
     (0x0100, 0x017F), 
     (0x0180, 0x024F), 
     (0x2C60, 0x2C7F), 
     (0x16A0, 0x16F0), 
     (0x0370, 0x0377), 
     (0x037A, 0x037E), 
     (0x0384, 0x038A), 
     (0x038C, 0x038C), 
    ] 

    alphabet = [ 
     get_char(code_point) for current_range in include_ranges 
      for code_point in range(current_range[0], current_range[1] + 1) 
    ] 
    return ''.join(random.choice(alphabet) for i in range(length)) 

if __name__ == '__main__': 
    print('A random string: ' + get_random_unicode(10)) 
+0

Спасибо, Джейкоб. Были ли проблемы при запуске этого кода в Python 2.7? – morfys

+1

@morfys Это не так, но я только что отредактировал его, чтобы он это сделал. Спасибо за вопрос. –

+0

Большое спасибо, Джейкоб! – morfys

2

Следит код, печать любой печатаемый символ UTF-8:

print(''.join(tuple(chr(l) for l in range(1, 0x10ffff) 
        if chr(l).isprintable()))) 

Все персонажи присутствуют, даже те, которые не обрабатываются используемого шрифта. and not chr(l).isspace() может быть добавлен, чтобы отфильтровать все пробельные символы. (включая вкладку)

+0

На самом деле это не даст вам случайную строку, хотя, конечно, вы можете просто использовать ['random.sample'] (https://docs.python.org/2/library/random.html#random.sample) вместо этого 'print'. – l0b0

+0

'random.sample' не заменяет элементы, которые он уже нарисовал. –

+0

Так что вместо этого используйте 'random.choices'. – gimboland

Смежные вопросы