C#中如何实现String.Normalize(FormD)的反向韩文字符组合功能
韩文兼容字母组合为完整音节的实现方案
问题根因
你调用无参Normalize()默认使用NormalizationForm.FormC归一化格式,无法完成组合的核心原因是:
- 你输入的
ㄱㅗㅇㅑㅇㅇㅣ属于韩文兼容字母(Hangul Compatibility Jamo,码位范围U+3130~U+318F),这类字符是为了兼容古旧编码设计的,Unicode标准没有定义它们的组合映射规则 - 你用
NormalizationForm.FormD分解고양이得到的是标准Hangul Jamo字符,分属初声(辅音开头)、中音(元音)、终声(辅音收尾)三个独立分区,和你手动输入的兼容Jamo不是同一套码位
实现方案
需要分两步完成转换:
- 建立兼容Jamo到标准Jamo的映射表,把输入的兼容字符转换为可组合的标准Jamo序列
- 对标准Jamo序列调用
Normalize(NormalizationForm.FormC)即可自动组合为完整韩文音节
C# 实现代码
using System; using System.Collections.Generic; using System.Text; public static class HangulCombiner { // 兼容Jamo转标准初声映射 private static readonly Dictionary<char, char> CompatToStandardChoseong = new() { {'ㄱ', '\u1100'}, {'ㄲ', '\u1101'}, {'ㄴ', '\u1102'}, {'ㄷ', '\u1103'}, {'ㄸ', '\u1104'}, {'ㄹ', '\u1105'}, {'ㅁ', '\u1106'}, {'ㅂ', '\u1107'}, {'ㅃ', '\u1108'}, {'ㅅ', '\u1109'}, {'ㅆ', '\u110A'}, {'ㅇ', '\u110B'}, {'ㅈ', '\u110C'}, {'ㅉ', '\u110D'}, {'ㅊ', '\u110E'}, {'ㅋ', '\u110F'}, {'ㅌ', '\u1110'}, {'ㅍ', '\u1111'}, {'ㅎ', '\u1112'} }; // 兼容Jamo转标准中音映射 private static readonly Dictionary<char, char> CompatToStandardJungseong = new() { {'ㅏ', '\u1161'}, {'ㅐ', '\u1162'}, {'ㅑ', '\u1163'}, {'ㅒ', '\u1164'}, {'ㅓ', '\u1165'}, {'ㅔ', '\u1166'}, {'ㅕ', '\u1167'}, {'ㅖ', '\u1168'}, {'ㅗ', '\u1169'}, {'ㅘ', '\u116A'}, {'ㅙ', '\u116B'}, {'ㅚ', '\u116C'}, {'ㅛ', '\u116D'}, {'ㅜ', '\u116E'}, {'ㅝ', '\u116F'}, {'ㅞ', '\u1170'}, {'ㅟ', '\u1171'}, {'ㅠ', '\u1172'}, {'ㅡ', '\u1173'}, {'ㅢ', '\u1174'}, {'ㅣ', '\u1175'} }; // 兼容Jamo转标准终声映射 private static readonly Dictionary<char, char> CompatToStandardJongseong = new() { {'ㄱ', '\u11A8'}, {'ㄲ', '\u11A9'}, {'ㄳ', '\u11AA'}, {'ㄴ', '\u11AB'}, {'ㄵ', '\u11AC'}, {'ㄶ', '\u11AD'}, {'ㄷ', '\u11AE'}, {'ㄹ', '\u11AF'}, {'ㄺ', '\u11B0'}, {'ㄻ', '\u11B1'}, {'ㄼ', '\u11B2'}, {'ㄽ', '\u11B3'}, {'ㄾ', '\u11B4'}, {'ㄿ', '\u11B5'}, {'ㅀ', '\u11B6'}, {'ㅁ', '\u11B7'}, {'ㅂ', '\u11B8'}, {'ㅄ', '\u11B9'}, {'ㅅ', '\u11BA'}, {'ㅆ', '\u11BB'}, {'ㅇ', '\u11BC'}, {'ㅈ', '\u11BD'}, {'ㅊ', '\u11BE'}, {'ㅋ', '\u11BF'}, {'ㅌ', '\u11C0'}, {'ㅍ', '\u11C1'}, {'ㅎ', '\u11C2'} }; public static string CombineCompatJamo(string compatJamoText) { StringBuilder standardJamoBuilder = new StringBuilder(); int position = 0; while (position < compatJamoText.Length) { // 匹配音节开头的初声 if (CompatToStandardChoseong.TryGetValue(compatJamoText[position], out char choseong)) { standardJamoBuilder.Append(choseong); position++; // 匹配后续的中音 if (position < compatJamoText.Length && CompatToStandardJungseong.TryGetValue(compatJamoText[position], out char jungseong)) { standardJamoBuilder.Append(jungseong); position++; // 匹配可选的终声,需判断是否为下一个音节的初声 if (position < compatJamoText.Length && CompatToStandardJongseong.TryGetValue(compatJamoText[position], out char jongseong)) { bool isJongseong = true; if (position + 1 < compatJamoText.Length) { if (CompatToStandardJungseong.ContainsKey(compatJamoText[position + 1])) { isJongseong = false; } } if (isJongseong) { standardJamoBuilder.Append(jongseong); position++; } } } } else { // 非韩文字符直接保留 standardJamoBuilder.Append(compatJamoText[position]); position++; } } // 标准Jamo序列归一化后即可得到组合后的完整音节 return standardJamoBuilder.ToString().Normalize(NormalizationForm.FormC); } } // 测试调用 public static void Test() { string input = "ㄱㅗㅇㅑㅇㅇㅣ"; string result = HangulCombiner.CombineCompatJamo(input); Console.WriteLine(result); // 输出:고양이 }
上述映射表覆盖了常用韩文字母,如需处理生僻组合,补充对应映射关系即可。
内容的提问来源于stack exchange,提问作者Damn Vegetables
相关产品推荐
相关产品推荐

