regex 总览待审核
实战 · 受控文本输入

受控文本输入框:按字形限长 · 注入控制字符 · twemoji 渲染

把本系列拆过的几个 Unicode 概念合到一个真实的输入组件里。处理一段自由文本,三件事最容易出错: 限长该数用户感知的「一个字符」(字素簇)而非 .length(UTF-16 码元); 文本里可能混入看不见的控制字符(零宽与隐形字符U+202E bidi 反转), 需要能受控注入、也能被察觉;同一个 emoji 在各平台字形不一(Basic_Emoji), 要一致显示就用 twemoji 的 SVG。文本框本身用 @vega/smart-input 接管(IME / 撤销 / 拦截), 只描述一个 formatter。

受控编辑区:按字形限长 + 字符注入 + emoji 内联 SVG

左边的编辑区由 createSmartInput 接管。因为<textarea> 渲染不了内联图片, 这里改用 contenteditable + smart-input 的 renderHtml 富渲染:每个 twemoji 支持的 emoji 在编辑区里直接用 SVG 显示(取不到 SVG 才回退系统字体);为保住光标 / 计数正确,SVG 仅作覆盖层,底层仍是真实码点 (满足 textContent === text)。normalize 把超过 24 个字形的部分截断——按 Intl.Segmenter 的 grapheme 计数,🤦🏼‍♂️(7 个码元)只算 1 个、截断不切碎 ZWJ 序列。 右边两种方式把字符插到光标处:常用不可见 / 控制字符的快捷 chip、自定义 codepoint 输入 (支持一次填多个,如 U+202E U+2322,合法时下方实时给出渲染结果);下方还有按 Unicode 分组的 emoji 选择器。 注入控制字符后,计数器会立刻显示「字形数」「隐形字符」双双变化——验证了「肉眼一个都没多,限额却被悄悄吃掉」。

自定义 codepoint
emoji 选择器 · 按 Unicode 分组
为什么限长要按字形:若按 str.length(UTF-16 码元)限长,一个 😀 占 2、🤦🏼‍♂️ 占 7, 用户「打了几个字」与系统「数出几格」对不上,截断点还可能落在代理对中间产生半个乱码字符。按 grapheme 计数 + 在字形边界截断才与用户感知一致。
U+202E 的危险:点「RLO」注入 U+202E 后,它把后文显示顺序反转——文件名 invoice‮gpj.exe 看着像 invoiceexe.jpg,这就是 Trojan Source。控制字符看不见却真实存在,受控输入应当能注入演示、更要能审计揪出。
twemoji 是什么:一套开源 emoji 图形(原 Twitter 的 Twemoji,现由社区 jdecked/twemoji 维护), 提供每个 emoji 的 SVG / PNG。把页面里的 emoji 替换成 twemoji 资源,就能让所有用户看到同一个字形,不再受设备 emoji 字体版本影响。 本页直接从 CDN 按码点取 SVG;若某序列 twemoji 未收录(取不到资源),自动回退为系统字体字形。
和前面几页的关系:「文件名」取码点用的正是 字符的编码 里 code point ⇄ UTF-16 的换算, ZWJ / VS16 的取舍来自 Basic_EmojiRGI 序列两页拆过的序列结构。