#!/usr/bin/env python3 """ Generate binary tables for: a) is char X alphanumeric? (letter or decimal digit) b) is char whitespace? """ import os import struct import urllib.request DATA_DIR = './data' OUT_DIR = './out' os.makedirs(DATA_DIR, exist_ok=True) os.makedirs(OUT_DIR, exist_ok=True) UNICODE_DATA_URL = 'https://www.unicode.org/Public/UCD/latest/ucd/UnicodeData.txt' UNICODE_DATA_PATH = os.path.join(DATA_DIR, 'UnicodeData.txt') if not os.path.exists(UNICODE_DATA_PATH): print(f"Downloading {UNICODE_DATA_URL}...") urllib.request.urlretrieve(UNICODE_DATA_URL, UNICODE_DATA_PATH) print("Downloaded") def parse_unicode_data(): """Parse UnicodeData.txt and yield (codepoint, category, name)""" with open(UNICODE_DATA_PATH, 'r', encoding='utf-8') as f: for line in f: line = line.strip() if not line: continue parts = line.split(';') if len(parts) < 3: continue codepoint = int(parts[0], 16) name = parts[1] category = parts[2] # Handle ranges (First/Last) if name.endswith(', First>'): range_start = (codepoint, category, name) continue elif name.endswith(', Last>') and 'range_start' in locals(): start_cp, start_cat, start_name = range_start base_name = start_name.replace(', First>', '').replace('<', '') for cp in range(start_cp, codepoint + 1): yield (cp, start_cat, f"<{base_name}>") del range_start continue yield (codepoint, category, name) def is_alphanumeric(category: str, codepoint: int) -> bool: """Check if category indicates alphanumeric (letter or decimal digit)""" return category.startswith('L') or category == 'Nd' def is_whitespace(category: str, codepoint: int) -> bool: """Check if character is whitespace""" if category in ('Zs', 'Zl', 'Zp'): return True # Common control whitespaces: \t\n\r\f\v and others return codepoint in (0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x1C, 0x1D, 0x1E, 0x1F, 0x85, 0xA0) def build_bitmap(check_func, max_codepoint=0x10FFFF): """Build a bitmap for the given check function""" # We'll use a byte array where each bit represents a codepoint size = (max_codepoint + 8) // 8 bitmap = bytearray(size) for cp, cat, _ in parse_unicode_data(): if check_func(cat, cp): byte_idx = cp // 8 bit_idx = cp % 8 bitmap[byte_idx] |= (1 << bit_idx) return bitmap def write_binary_file(path: str, bitmap: bytearray, max_codepoint: int): """Write binary file with header: magic, version, max_codepoint, data""" with open(path, 'wb') as f: # Magic: 'XICU' (0x58494355) f.write(struct.pack('