【记日本姓名处理引发的有趣故事】

记日本姓名处理引发的有趣故事

写在前面

最近在做日本保险项目的时候,遇到了一个有意思的问题:为什么同一个客户的名字,系统里会保存好几份?什么汉字版、片假名版、全角版、半角版…一个名字能玩出这么多花样?

好奇之下,我研究了一下日本文字的历史,发现这背后有着千年的文化演变,也有现代系统设计的智慧。今天就来聊聊这个有趣的话题。


第一部分:日本文字体系的历史演进

1.1 汉字的传入与本土化(5-6世纪)

日本原本没有文字系统。公元5-6世纪,汉字随着佛教和中国文化传入日本。最初,日本人直接使用汉字记录日语,但很快发现了问题:

语言结构的根本差异:

汉语是孤立语,依靠语序和虚词日语是黏着语,有复杂的语法变化和助词系统汉字无法有效表达日语的语法结构

1.2 平假名的诞生(9世纪)

社会背景:

平安时代(794-1185),日本贵族文化兴盛女性作家需要书写工具,但正式场合使用汉字被视为男性特权女性文学(如《源氏物语》)催生了简化书写的需求

平假名的形成机制:


汉字草书 → 简化 → 平假名
安 → あ (a)
以 → い (i)
宇 → う (u)
衣 → え (e)
於 → お (o)

1.3 片假名的诞生(9世纪)

社会背景:

佛教僧侣研读汉文经典,需要标注读音和训诂在汉文旁边添加注释,需要简洁的符号系统

片假名的形成机制:


汉字楷书取偏旁部首 → 片假名
加 → カ (ka)
伊 → イ (i)
宇 → ウ (u)
江 → エ (e)
於 → オ (o)

1.4 片假名的现代用途演变

明治维新后(1868年起):

外来语标记的主流工具

西方科技、文化大量涌入需要标记外来词汇:コーヒー(coffee)、コンピューター(computer)片假名成为”外来语专用文字”

强调和突出

广告、标语中使用片假名吸引注意类似于西文中的斜体或粗体效果

拟声词拟态词

ドキドキ(心跳声)、キラキラ(闪亮)与平假名的拟声词形成风格对比

姓名标记的特殊用途

外国人姓名:全部用片假名标记日本人姓名的注音:在汉字旁边用片假名标注读音(振り仮名)姓名统一化:在需要统一格式的场景(如保险、金融),用片假名消除汉字歧义


第二部分:日本姓名的复杂性与业务挑战

2.1 日本姓名的多重表达

一个日本人的姓名,在不同场景下有多种表达方式:

案例:山田太郎(Yamada Taro)

表达形式 示例 用途场景
汉字姓名 山田太郎 正式文件、身份证明
平假名姓名 やまだたろう 儿童读物、辅助阅读
片假名姓名 ヤマダタロウ 保险、金融、数据库标准化
罗马字姓名 Yamada Taro 国际交流、护照

为什么保险业务要用片假名?

消除汉字歧义

同音异字:斎藤/斉藤/齊藤/齋藤(Saito)异体字:渡辺/渡邊/渡邉(Watanabe)片假名统一为:サイトウ、ワタナベ

统一检索标准

汉字数据库查询困难(JIS编码、Unicode差异)片假名是标准的46个字符,易于索引和匹配

数据清洗和去重

客户可能用不同汉字写同一个名字片假名可以作为”标准化姓名”进行去重

支持外国人客户

外国人在日本通常用片假名登记系统需要同时支持日本人和外国人

2.2 业务场景中的姓名问题

问题1:同一个人,多种汉字写法


投保时:斎藤一郎
理赔时:斉藤一郎
查询时:查无此人 ❌

问题2:全角半角混用


用户输入A:ヤマダ タロウ(全角片假名 + 全角空格)
用户输入B:ヤマダ タロウ(半角片假名 + 半角空格)
系统判断:两个不同的人 ❌

问题3:浊音、半浊音、长音的变体


が(浊音) vs か(清音)
ガ(全角) vs ガ(半角+浊点)
パ(半浊音) vs ハ(清音)
コーヒー vs コーヒイ(长音符号 vs イ)

问题4:外来语的音译差异


Smith:スミス / ス ミ ス / すみす
McDonald:マクドナルド / マクドナード / マックドナルド

第三部分:技术实现 – 数据模型设计

3.1 双层存储架构

说到系统设计,我们采用了”原始数据 + 清洗数据”的双层存储模型。简单来说,就像你拍照片时保存RAW格式和JPG格式一样,既保留原片,又有方便使用的处理版。

数据库里大概是这样的结构:


人员表字段:
├── 原始数据 (用户输入的原汁原味版本)
│   ├── originSurname           // 原始汉字姓
│   ├── originGivenName         // 原始汉字名
│   ├── originLocalSurname      // 原始片假名姓
│   └── originLocalGivenName    // 原始片假名名
│
├── 清洗后数据 (标准化处理后的版本)
│   ├── surname                 // 清洗后汉字姓
│   ├── givenName               // 清洗后汉字名
│   ├── localSurname            // 清洗后片假名姓
│   └── localGivenName          // 清洗后片假名名
│
└── 拼接全名 (方便查询)
    ├── fullName                // 汉字全名
    └── localFullName           // 片假名全名

设计理念:

层次 字段类型 用途 示例
原始层 origin* 保留用户输入,用于展示和审计 originLocalSurname: “ヤマダ” (半角)
清洗层 surname/localSurname 标准化后用于业务逻辑和匹配 localSurname: “ヤマダ” (全角)
聚合层 fullName/localFullName 姓名拼接,用于全文检索和去重 localFullName: “ヤマダタロウ”

为什么要保留原始数据?

数据可追溯性:了解客户真实输入,便于问题排查业务需求变化:产品经理可能会改主意。比如最开始我们展示清洗后的数据,后来发现用户更习惯看自己输入的格式,又改回去展示原始数据了合规要求:金融行业需要保留客户原始信息,审计的时候要查

3.2 差异化的清洗策略

关键发现:汉字和片假名采用相反的全半角转换策略


// DataCleanerConfig.java

// 片假名清洗管道:全角→半角
@Bean
public RuleCleanerPipeline japanesePseudonymCleaningPipeline(){
    return new RuleCleanerPipeline()
        .build(new CharLower2UpperCleaner())         // 1. 小写→大写
        .build(new DeleteSpecialCharacterCleaner())  // 2. 删除特殊字符
        .build(new PuzzledAndPromotingSoundCleaner())// 3. 拗音处理(きゃ→キャ)
        .build(new HomophoneUnificationCleaner())    // 4. 同音统一
        .build(new CloseSoundCleaner())              // 5. 近音处理
        .build(new MacronUnificationCleaner())       // 6. 长音统一(ー)
        .build(new DeleteBracketCleaner())           // 7. 删除括号
        .build(new AllBlankSpaceCleaner())           // 8. 删除所有空格
        .build(new BracketUnificationCleaner())      // 9. 括号统一
        .build(new StringHalfCleaner());             // 10. 全角→半角 ★
}

// 汉字清洗管道:半角→全角
@Bean
public RuleCleanerPipeline chineseCharacterNameCleaningPipeline(){
    return new RuleCleanerPipeline()
        .build(new HeadAndTailBlankSpaceCleaner())   // 1. 首尾空格删除
        .build(new CharLower2UpperCleaner())         // 2. 小写→大写
        .build(new PuzzledAndPromotingSoundCleaner())// 3. 拗音处理
        .build(new DeleteSpecialCharacterCleaner())  // 4. 删除特殊字符
        .build(new CloseSoundCleaner())              // 5. 近音处理
        .build(new MacronUnificationCleaner())       // 6. 长音统一
        .build(new HomophoneUnificationCleaner())    // 7. 同音统一
        .build(new DeleteBracketCleaner())           // 8. 删除括号
        .build(new BracketUnificationCleaner())      // 9. 括号统一
        .build(new StringFullCleaner());             // 10. 半角→全角 ★
}

为什么片假名转半角,汉字转全角?

文字类型 转换方向 技术原因 业务原因
片假名 全角→半角 半角片假名占1字节,节省存储;ASCII兼容性好 日本金融行业传统,早期系统多用半角
汉字 半角→全角 汉字本身就是全角字符,半角汉字不规范 保持视觉一致性,避免显示问题

示例对比:


片假名清洗:
输入:"ヤマダ タロウ"(全角片假名 + 全角空格)
输出:"ヤマダタロウ"(半角片假名,无空格)

汉字清洗:
输入:"山田 太郎"(全角汉字 + 半角空格)
输出:"山田太郎"(全角汉字,无空格)

第四部分:数据清洗管道的深度解析

4.1 管道模式(Pipeline Pattern)

系统采用责任链模式实现数据清洗:


原始输入 → Cleaner1 → Cleaner2 → ... → CleanerN → 清洗输出

核心类:RuleCleanerPipeline


public class RuleCleanerPipeline {
    private List<Cleaner> cleaners = new ArrayList<>();

    public RuleCleanerPipeline build(Cleaner cleaner) {
        this.cleaners.add(cleaner);
        return this;  // 链式调用
    }

    public String process(String input) {
        String result = input;
        for (Cleaner cleaner : cleaners) {
            result = cleaner.clean(result);
        }
        return result;
    }
}

4.2 十大清洗器详解

1. CharLower2UpperCleaner – 小写转大写

输入:yamada tarou
输出:YAMADA TAROU

原因:统一大小写,避免匹配失败

2. DeleteSpecialCharacterCleaner – 删除特殊字符

输入:山田@太郎#
输出:山田太郎

原因:用户可能误输入标点符号

3. PuzzledAndPromotingSoundCleaner – 拗音处理

拗音:きゃ(kya)、しゅ(shu)、ちょ(cho)
输入:きょうこ(Kyoko)
输出:キョウコ

原因:拗音是两个假名组合发一个音,需要正确识别

4. HomophoneUnificationCleaner – 同音统一

输入:サイトウ(齋藤/斎藤/斉藤)
输出:サイトウ(统一标准)

原因:日语有大量同音异字,需要规范化

5. CloseSoundCleaner – 近音处理

清音 vs 浊音:
か(ka) → が(ga)
は(ha) → ば(ba) / ぱ(pa)

输入变体可能混用,需要统一为标准形式
6. MacronUnificationCleaner – 长音统一

长音符号的多种表示:
コーヒー(标准)
コーヒイ(用イ替代长音符)
コーヒ(省略)

统一为:コーヒー

原因:外来语长音表示不统一

7. DeleteBracketCleaner – 删除括号

输入:山田(太郎)
输出:山田太郎

原因:去除注释性内容

8. AllBlankSpaceCleaner – 删除所有空格

输入:ヤマダ タロウ(全角空格)
      ヤマダ タロウ(半角空格)
输出:ヤマダタロウ

原因:统一格式,避免空格差异导致匹配失败

9. BracketUnificationCleaner – 括号统一

全角括号:()
半角括号:()
统一为特定格式
10. StringHalfCleaner / StringFullCleaner – 全半角转换

StringHalfCleaner(片假名用):
ヤマダ(全角,3字符) → ヤマダ(半角,3字符)

StringFullCleaner(汉字用):
ヤマダ(半角) → ヤマダ(全角)

4.3 清洗流程实例

输入示例:


originLocalSurname: "ヤマダ "(全角片假名 + 全角空格)
originLocalGivenName: "たろう"(平假名)

清洗过程:


// DataCleanerLogic.java
public void cleaner(PolicyCustomerNewComponentRequestDTO dto) {
    // 片假名清洗
    String cleanLocalSurname = japanesePseudonymCleaningPipeline
        .process(dto.getOriginLocalSurname());
    // "ヤマダ " → "YAMADA" → "YAMADA" → ... → "ヤマダ"

    dto.setLocalSurname(cleanLocalSurname);

    // 平假名→片假名转换
    String cleanLocalGivenName = japanesePseudonymCleaningPipeline
        .process(dto.getOriginLocalGivenName());
    // "たろう" → "TAROU" → "タロウ" → ... → "タロウ"

    dto.setLocalGivenName(cleanLocalGivenName);
}

输出结果:


localSurname: "ヤマダ"
localGivenName: "タロウ"
localFullName: "ヤマダタロウ"

第五部分:客户去重与五项规则

5.1 业务场景:如何判断是否为同一个人?

在保险业务中,客户可能通过多个渠道、多次投保,系统需要识别是否为同一个人,避免重复建档。

挑战:

姓名可能用不同汉字联系方式可能变更证件号码未必每次都提供

5.2 五项规则(Five Rule Matching)


// RuleEnum.java
public enum RuleEnum {
    FIRST_RULE(1, "channelCode + channelUserNo"),     // 渠道唯一ID
    SECOND_RULE(2, "cnName + birthday + email"),      // 汉名 + 生日 + 邮箱
    THIRD_RULE(3, "cnName + birthday + phoneNo"),     // 汉名 + 生日 + 手机
    FORTH_RULE(4, "jpName + birthday + email"),       // 日名 + 生日 + 邮箱
    FIFTH_RULE(5, "jpName + birthday + phoneNo");     // 日名 + 生日 + 手机
}

优先级顺序:


渠道用户 > 汉名匹配 > 日名匹配

执行逻辑:


// Order 101 - 渠道用户优先
@Handler(order = 101)
class PersonChannelParamLogic {
    // 如果能通过渠道ID找到唯一客户,直接返回
}

// Order 102 - 汉名 + 生日匹配
@Handler(order = 102)
class ChinaNameParamLogic {
    PersonDO query = new PersonDO();
    query.setFullName(surname + givenName);  // 汉字全名
    query.setBirthday(birthday);
    List<PersonDO> results = personDAO.select(query);
    // 如果找到唯一匹配,返回
}

// Order 103 - 日名 + 生日匹配
@Handler(order = 103)
class JapanNameParamLogic {
    PersonDO query = new PersonDO();
    query.setLocalFullName(localSurname + localGivenName);  // 片假名全名
    query.setBirthday(birthday);
    List<PersonDO> results = personDAO.select(query);
}

5.3 为什么片假名匹配的优先级更低?

原因分析:

汉字更稳定

身份证、户口本用汉字汉字是法定姓名,片假名是辅助标记

片假名可能有变体

同一个人可能用不同的片假名拼法外来语音译没有标准答案

汉字 + 生日的可靠性更高

汉字姓名 + 出生日期的组合,重复概率极低片假名因为只有46个字符,重名率较高

案例:


张三(中国人在日本):
- 汉字姓名:張三
- 片假名:チョウサン / チャンサン / ジャンサン(多种拼法)
→ 汉字匹配更可靠

第六部分:业务需求的演变与技术应对

6.1 需求变更:从清洗数据到原始数据

2025年10月28日的关键提交:


// 提交信息:[SOMPO-16952] fix(customer):修复保单客户姓名字段取值逻辑
// 文件:QueryPolicyCustomerHandler.java

// ===== 修改前 =====
String surname = policyCustomer.getSurname();           // 清洗后汉字姓
String localSurname = policyCustomer.getLocalSurname(); // 清洗后片假名姓

// ===== 修改后 =====
String surname = policyCustomer.getOriginSurname();           // 原始汉字姓
String localSurname = policyCustomer.getOriginLocalSurname(); // 原始片假名姓

为什么要这样改?

技术视角:

清洗后数据统一为半角片假名,但显示时可能造成视觉不适原始数据保留了用户输入的全角格式,显示效果更自然

业务视角:

客户投保时填写的是全角片假名在保单、理赔单据上显示半角片假名,客户可能无法识别日本客户习惯看到全角片假名

示例对比:


原始输入(用户填写):
姓名:山田太郎
片假名:ヤマダ タロウ(全角 + 空格)

清洗后存储:
fullName: 山田太郎
localFullName: ヤマダタロウ(半角,无空格)

显示给用户:
方案A(旧):ヤマダタロウ(半角,客户可能觉得奇怪)
方案B(新):ヤマダ タロウ(全角,符合客户预期)✓

6.2 需求变更2:删除全角转半角逻辑

2025年11月12日的提交:


// 提交信息:[SOMPO-16952] 删除全角转半角逻辑
// 文件:SaveCustomerQuestionHandler.java

// ===== 修改前 =====
if (customerInfo != null && StringUtils.isNotBlank(customerInfo.getName2())) {
    customerInfo.setName2(
        nameCleaningPipeline.process(customerInfo.getName2())
    );
}

// ===== 修改后 =====
// 注释掉上述代码

为什么删除?

推测的业务原因:

**客户问题表(customer_question)**是用户反馈的原始问题,需要保留原汁原味清洗可能丢失信息,用户输入”ヤマダ タロウ”如果清洗为”ヤマダタロウ”,客服人员无法还原用户真实输入审计和追溯需求,保留原始数据便于问题排查

技术启示:

并非所有数据都需要清洗需要区分”用于匹配的数据”和”用于展示的数据”清洗规则不是一成不变的,要随业务调整


第七部分:技术难点与解决方案

7.1 难点1:全角半角的Unicode差异

技术背景:


全角片假名:U+30A0 ~ U+30FF(Katakana)
半角片假名:U+FF65 ~ U+FF9F(Halfwidth Katakana)

ヤ(全角):U+30E4(3字节UTF-8)
ヤ(半角):U+FF94(3字节UTF-8)

Java字符串比较:
"ヤ".equals("ヤ") → false

解决方案:StringHalfCleaner / StringFullCleaner


public class StringHalfCleaner implements Cleaner {
    @Override
    public String clean(String input) {
        if (input == null) return null;
        StringBuilder sb = new StringBuilder();
        for (char c : input.toCharArray()) {
            if (c >= 0x30A0 && c <= 0x30FF) {
                // 全角片假名 → 半角片假名
                sb.append((char)(c - 0x30A0 + 0xFF65));
            } else {
                sb.append(c);
            }
        }
        return sb.toString();
    }
}

7.2 难点2:浊音半浊音的组合字符

问题:


が 可以表示为:
1. U+304C(单个字符)
2. U+304B + U+3099(か + 浊点组合)

数据库中可能同时存在两种编码形式,导致查询失败

解决方案:Unicode正规化


import java.text.Normalizer;

String normalized = Normalizer.normalize(input, Normalizer.Form.NFC);
// NFC: Canonical Decomposition, followed by Canonical Composition
// 将组合字符统一为单个字符

7.3 难点3:外来语长音的变体

问题:


"コーヒー"(Coffee)的多种写法:
1. コーヒー(标准长音符号 ー U+30FC)
2. コーヒイ(用イ代替长音)
3. コーヒ(省略长音)
4. コ-ヒー(用半角连字符代替长音)

解决方案:MacronUnificationCleaner


public class MacronUnificationCleaner implements Cleaner {
    @Override
    public String clean(String input) {
        return input
            .replaceAll("ー", "ー")      // 统一长音符号
            .replaceAll("-", "ー")       // 半角连字符→长音
            .replaceAll("イイ$", "イー"); // 词尾重复イ→长音
    }
}

7.4 难点4:同音异字的汉字姓名

问题:


齋藤(Saito)的汉字变体:
齋藤、斎藤、斉藤、齊藤、斋藤

客户投保时用"齋藤",理赔时写"斉藤",系统查无此人

解决方案:片假名作为标准化key


// 保存时:
person.setFullName("齋藤一郎");             // 汉字全名(可能有变体)
person.setLocalFullName("サイトウイチロウ"); // 片假名全名(标准化)

// 查询时优先级:
// 1. 先用渠道ID查
// 2. 再用汉字 + 生日查
// 3. 最后用片假名 + 生日查(兜底方案)

PersonDO query = new PersonDO();
query.setLocalFullName("サイトウイチロウ");  // 不管汉字怎么写,片假名统一
query.setBirthday(birthday);
List<PersonDO> results = personDAO.select(query);

第八部分:与数据库和ES的联动

8.1 数据流转路径


用户输入
  ↓
【Origin字段存储】原始数据保存(originSurname, originLocalSurname等)
  ↓
【清洗管道】
  ├→ 汉字清洗管道(半角→全角)
  └→ 片假名清洗管道(全角→半角)
  ↓
【Cleaned字段存储】清洗后数据保存(surname, localSurname等)
  ↓
【全名拼接】fullName = surname + givenName
            localFullName = localSurname + localGivenName
  ↓
【数据库INSERT/UPDATE】Person表
  ↓
【Binlog捕获】MySQL Binlog
  ↓
【消息队列】Kafka
  ↓
【ES同步】Elasticsearch索引更新

8.2 Elasticsearch索引设计


{
  "mappings": {
    "properties": {
      "party_id": { "type": "long" },
      "full_name": {
        "type": "text",
        "analyzer": "ik_max_word",
        "fields": {
          "keyword": { "type": "keyword" }
        }
      },
      "local_full_name": {
        "type": "text",
        "analyzer": "japanese_analyzer",
        "fields": {
          "keyword": { "type": "keyword" }
        }
      },
      "birthday": { "type": "date" },
      "phone_no": { "type": "keyword" },
      "email": { "type": "keyword" }
    }
  }
}

日语分词器配置:


{
  "analysis": {
    "analyzer": {
      "japanese_analyzer": {
        "type": "custom",
        "tokenizer": "kuromoji_tokenizer",
        "char_filter": ["icu_normalizer"],
        "filter": ["katakana_readingform", "lowercase"]
      }
    }
  }
}

8.3 查询优化策略

策略1:使用片假名进行模糊查询


// 用户输入:サイトウ
// ES查询:
{
  "query": {
    "match": {
      "local_full_name": "サイトウ"
    }
  }
}

// 可以匹配到:
// サイトウイチロウ(斉藤一郎)
// サイトウジロウ(斎藤二郎)

策略2:多字段联合查询


{
  "query": {
    "bool": {
      "should": [
        { "match": { "full_name": "斉藤" }},
        { "match": { "local_full_name": "サイトウ" }}
      ],
      "minimum_should_match": 1
    }
  }
}

第九部分:最佳实践与未来展望

10.1 姓名处理的最佳实践

1. 双层存储是必须的


✓ 正确:保留origin字段 + cleaned字段
✗ 错误:只保留清洗后数据

2. 清洗规则要可配置


// 不同业务场景可能需要不同的清洗规则
@Configuration
public class DataCleanerConfig {
    @Bean("displayNamePipeline")  // 用于展示的清洗规则
    public RuleCleanerPipeline displayNamePipeline() { ... }

    @Bean("searchNamePipeline")   // 用于搜索的清洗规则
    public RuleCleanerPipeline searchNamePipeline() { ... }
}

3. 片假名是可靠的标准化key


// 汉字可能有变体,片假名相对稳定
PersonDO query = new PersonDO();
query.setLocalFullName(katakanaFullName);  // 优先用片假名查询
query.setBirthday(birthday);

4. 多规则匹配提高准确性


// 不要依赖单一字段,组合多个字段提高可靠性
渠道ID > 汉名+生日+邮箱 > 片假名+生日+手机

10.2 国际化系统的通用原则

基于日本姓名处理的经验,可以总结出适用于其他语言的通用原则:

1. 了解文字系统的历史和文化背景

韩国:汉字(한자)+ 谚文(한글)越南:汉字(Chữ Hán)+ 国语字(Chữ Quốc ngữ)印度:多种文字系统(Devanagari, Tamil, Bengali等)

2. 保留原始输入,提供标准化转换

阿拉伯语:从右到左书写,需要特殊处理泰语:没有空格分词,需要特殊分词器

3. 注意Unicode正规化

组合字符 vs 单个字符(é = e + ́)不同区块的相同字符(A = Latin A vs Α = Greek Alpha)

4. 多字段联合匹配

姓名 + 生日 + 证件号拼音 + 手机号 + 邮箱

10.3 未来优化方向

1. AI辅助姓名清洗


# 使用机器学习识别姓名变体
from transformers import BertForTokenClassification

model = BertForTokenClassification.from_pretrained("japanese-name-ner")
variants = model.predict("齋藤一郎")
# Output: ["斉藤一郎", "斎藤一郎", "サイトウイチロウ"]

2. 实时清洗 vs 离线清洗


// 实时清洗:用户输入时立即清洗,提供反馈
@PostMapping("/validate-name")
public NameValidationResponse validateName(String name) {
    String cleaned = namePipeline.process(name);
    return new NameValidationResponse(cleaned, suggestions);
}

// 离线清洗:定时批量清洗历史数据
@Scheduled(cron = "0 0 2 * * ?")
public void batchCleanHistoricalData() { ... }

3. 区块链存储原始数据


数据库:存储清洗后数据,用于业务查询
区块链:存储原始数据哈希,防止篡改,用于审计

结语

从公元9世纪日本僧侣在汉文经典旁边标注的简化符号,到21世纪现代保险系统中的数据清洗管道,片假名走过了1200年的演进历程。它最初是学术工具,后来成为外来语标记,如今在金融系统中扮演着”标准化姓名”的关键角色。

这个案例展示了技术如何服务于文化,文化如何塑造技术。在设计国际化系统时,我们不仅要理解Unicode、数据库、算法,更要理解文字背后的历史、社会背景和用户习惯。

技术是死的,文化是活的。优秀的系统设计,应该让技术适应文化,而非让文化迁就技术。


参考文献

《日本语言文字史》 – 日本文字演进历程Unicode Standard 15.0 – Katakana区块定义

全文完 | 字数:约12,000字

© 版权声明
THE END
如果内容对您有所帮助,就支持一下吧!
点赞0 分享
评论 抢沙发

请登录后发表评论

    暂无评论内容