# @finbheara/names 中文文档

规范地址：https://npmcn.com/package/%40finbheara/names/

版本：0\.31\.0
npm 元数据更新时间：2026-11-07T09:36:14.586Z
中文译文更新时间：2026-11-14T18:58:32.118Z
软件包许可：MIT

本文由上游 README 翻译，可能存在偏差，请结合原文核对 API、命令与配置。版权与许可归原作者所有。

原始 npm 页面：https://www.npmjs.com/package/%40finbheara/names
原文对照：https://npmcn.com/package/%40finbheara/names/?lang=original

## 关键信息（来自 npm 元数据）

- 包体积（解压后）：2.2 MB，106 个文件
- 模块格式：ES Module
- TypeScript 类型：包内自带
- Node.js 要求：\>=22\.3
- 运行依赖：1 个
- 首次发布：2026-09-30T19:28:30.018Z
- 最新版本发布：2026-11-07T09:36:14.390Z
- 近 30 天下载量：3357（2026-10-15 至 2026-11-13，npm 官方下载统计）
- 已发布版本数：34（近 12 个月 34 个）

## 中文简介

个人、学校和地名、姓氏-粒子词汇、分类词和人名正常化词典

## 安装

```sh
npm install @finbheara/names
```

也可以使用：`pnpm add @finbheara/names`、`yarn add @finbheara/names`、`bun add @finbheara/names`

## README

# @ finbhea/ 名称

实际打印的人名: 解析、 正常化、 比较、 分解 从学校和地名.

-   **拼音词典** (单位:千美元)`names.txt`: ~15 000人 姓名、地点、学校和 多词短语,每个标出它是什么.
-   **姓氏-粒子词汇**数字 : `Mac`, (中文(简体) ), `Ní`, (中文(简体) ), `O`, (中文(简体) ), `van`, (中文(简体) ), `de` 剩下的,还有.. 每个显示一个拼写.
-   **人名规范化**: 一个打印单元格, a `PersonName` 出来,有一个 canonial 显示窗体,文件密钥和匹配密钥.
-   **一个词组分类器**:这个字符串是一个人,一个学校或一个地方,在哪里 人结束 学校开始?
-   **计量工具**:通过上述所有内容运行一串名称流,并查看其内容 无法识别.

它建立在爱尔兰舞蹈比赛的结果单上 一个舞者的名字 以 `O'RERVTON, MOIRA`, (中文(简体) ), `Moira ORervton` 财务报告和审定财务报表 `Moira O Rervton`和学校的名字 连接在舞者身上 规则一般为盎格鲁语,爱尔兰语和欧洲语名.

```sh
npm install @finbheara/names
```

无害环境管理,节点为 22.3 或 Bun为 1.4.3. MIT。 无条目进口a `node:` 模块,因此每个条目 用于浏览器或工人的捆绑 `Lexicon.load`,它读取文件,需要节点 或Bun在呼叫时间.

## 入境点

只导入您使用的; `/lexicon`, (中文(简体) ), `/particles`, (中文(简体) ), `/normalize` 财务报告和审定财务报表 `/phonetic` 从不装入 分类器的开花桌子.

| 导入 | 什麽 |
| --- | --- |
| `@finbheara/names/normalize` | `PersonName`,它的工厂,比较,编曲,列表 |
| `@finbheara/names/lexicon` | `names.txt` 解析:旗帜、多词短语、拼写、角色 |
| `@finbheara/names/particles` | 粒子词汇 |
| `@finbheara/names/classifier` | 人/学校/地点分类和分类 |
| `@finbheara/names/phonetic` | 双元音:一个单词作为密钥听起来如何 |
| `@finbheara/names/measure` | 普查和分类评价 |
| `@finbheara/names` | 以上各项 |
| `@finbheara/names/names.txt` | 原始词典 |

## 将名称正常化

```ts
import { isNoNamePrint, personName } from "@finbheara/names/normalize";

const n = personName("WYRKOW NÍ MHAOLVARNA");
n.nn2;           // "NiMhaolvarna<<Wyrkow"      canonical display form
n.nn3;           // "NIMHAOLVARNA<<WYRKOW"      filing key
n.nn4;           // "NIMHAOLVARNA<WYRKOW"       order-free matching key
n.surnameKey();  // "NIMHAOLVARNA"
n.givenName();   // "WYRKOW"
n.surname;       // { particles: ["NÍ"], base: "MHAOLVARNA", tradition: "i", ... }
n.isPerson();    // true

personName("ORERVTON, MOIRA", "surname-first").nn2;  // "O'Rervton<<Moira"
personName("Foireann A").isTeam();                  // true: a team, not a person
personName("Kelsey Pearraillina - BN2018").refusal;       // { rule: "refuse-digit", ... }
personName("N/A").printsNoName();                   // true: a placeholder, no name printed
personName("").isEmpty();                           // true: nothing printed at all
isNoNamePrint("Not known");                         // true, from the print alone (no parse)
```

每个输入都有一个 `PersonName`; 一个没有人名的单元格 **拒绝**,而不是抛出: `isPerson()` 是虚假的, `refusal` 从NN2到NN2的每个关卡都读到 `PersonName.REFUSED` (单位:千美元)`"!!!INVALID"`) (中文(简体) ). 空牢房既不是个人也不是拒绝: 它会回答 `isEmpty()`。 。 。 . `printsNoName()` 对空单元格、无字母单元格来说是真实的 (单位:千美元)`???`)和一个占位符(`N/A`, (中文(简体) ), `TBA`, (中文(简体) ), `Unknown`, (中文(简体) ), `Not known`),无论哪个规则拒绝.

### 级别

| 职等 | 实值 | 大小写 | 口音 | 顶点 | 字段顺序 |
| --- | --- | --- | --- | --- | --- |
| `nn0` | 准确的页上说 | 保留 | 保留 | 保留 | 保留 |
| `nn1` | `nn0` 使用白空格、 引用、 控制字节和一个命名的腐败修复 | 保留 | 保留 | 已正常化 | 保留 |
| `nn2` | 条形显示形式(`Surname<<Given<Middle`(中文(简体) ) | 来源 | ASC 二届理事会 | 保留 | 保留 |
| `nn3` | 归档密钥 | 上层 | ASC 二届理事会 | 丢弃 | 保留 |
| `nn4` | 匹配的密钥 : 两个指纹是否同名 ? | 上层 | ASC 二届理事会 | 丢弃 | 丢弃 |

坚持关卡字符串,绝不是对象 : `nn2` 显示, `nn3` 作为关键。 读取存储 `nn2` 带回 `personNameFromIcao(nn2)` (或 `factory.fromIcao`) (中文(简体) ). 合同满了 [`docs/NAME-NORMALIZATION.md`](https://npmcn.com/package/%40finbheara/names/docs/NAME-NORMALIZATION.md)。 。 。 .

### 一个被损坏的指纹

其字节在路上出错(UTF-8读作Windows 1252,读取两次,读取为 Mac OS Roman,一个被丢弃的字节,一个被迷路的控制)这样说. `corruption` 每个运行的名称,以及 水平读取其修复,同时 `nn0` 保存原始打印 :

```ts
const n = personName("MÃ©abh Varane", "given-first");
n.nn0;              // "MÃ©abh Varane"
n.nn1;              // "Méabh Varane"
n.nn2;              // "Varane<<Meabh"
n.corruption?.kind; // "utf8-as-cp1252"
n.corruption?.spans; // [{ kind: "utf8-as-cp1252", at: 1, raw: "Ã©", repair: "é", confidence: 0.98 }]
```

`diagnoseNameCorruption(print, knownNameOf(lexicon))` 是赤线的相同答案。 A 类 prot 字节被读取为对照词典的通配符,并取出一个丢失的字母(U+FFFD)并 从来没有填满。 种类和信心在 [`docs/NAME-NORMALIZATION.md`](https://npmcn.com/package/%40finbheara/names/docs/NAME-NORMALIZATION.md), (中文(简体) ), _一个被损坏的指纹_。 。 。 .

### 工厂

`personName` 是默认工厂的短手: 一个笼罩在承诺的工厂 `names.txt`。当您需要其他选项时,请自行制作;工厂的选项是固定的 当它是制造的, 没有工厂可以改变别人的答案.

```ts
import { createCachingPersonNameFactory, createPersonNameFactory } from "@finbheara/names/normalize";

const names = createCachingPersonNameFactory({
  lexicon: myLexicon,             // a Lexicon or a (key) => spelling lookup; null for rules only
  traditions: null,               // no tradition lookup
  parenthetical: (aside) =>       // what "( … )" or "\" … \"" in a name cell means
    aside === "Ontario" ? { refuse: "refuse-location-alias" } : "strip",
  capacity: 100_000,              // memo size; 0 disables the memo
});
names.parse("Anna (Ontario) Mailtina").isPerson();  // false
names.parse("Lena (Xiaoyu) Zumock").nn2;           // "Zumock<<Lena"
names.stats();                                   // { hits, misses, evictions, size, capacity }

const uncached = createPersonNameFactory();      // parses every call
```

默认 `parenthetical` 处理器全边条 : `Pundeallina "Katie" Foxe` 实值 `Foxe<<Pundeallina`。 。 。 .

一个缓冲工厂每个打印一个条目, 和它的顺序是: 打印读取 与命令 `unknown` 和再次的顺序 决心是一分一分 对象。 过去 `capacity` (默认) `DEFAULT_PERSON_NAME_CAPACITY`,262,144) 最少 最近使用的入口被逐出; `stats().evictions` 数起他们.

共享默认工厂的容量可以设定为每个进程一次,在任何程序之前 透过它。 能力是唯一的选择,因为它是唯一的选择 未改变答案 :

```ts
import { configureDefaultPersonNameFactory, personName } from "@finbheara/names/normalize";

configureDefaultPersonNameFactory({ capacity: 1_000_000 }); // ~1 KB an entry
personName("Moira O'Rervton");
configureDefaultPersonNameFactory({ capacity: 10 });        // throws: already made
```

一旦默认工厂存在,它就会抛出, 无论是先前的呼叫还是第一个 `personName`, (中文(简体) ), `personNameFromIcao` 或者说 `defaultPersonNameFactory()` 对.

### 文件的名称顺序

`deriveNameFormat` 读取 ONE 文件的名称单元格(结果表、名册、 并说它是用哪个顺序打印的,作为概率 `First Last`, (中文(简体) ), `Last, First` 财务报告和审定财务报表 `Last First`,与 `"unknown"` 在那里,没有人能清除阈值或 文档打印两个命令。 它还提出报告 `hasSchool` 财务报告和审定财务报表 `hasLocation` (做大多数单元格) 随身携带一个学校或一个地方的名字之后?),每个指纹读取,所以打电话者可以脱去 解析前的那些部分.

```ts
import { createSegmenter } from "@finbheara/names/classifier";
import { Lexicon } from "@finbheara/names/lexicon";
import { deriveNameFormat, nameFormatOrder, readNameCell } from "@finbheara/names/normalize";

// invented names, in a lexicon of their own
const lexicon = Lexicon.fromText("Zelvine:F\nOramie:F\nTalwyn:F\nQuorrish:L\nVantrell:L\nOspindle:L\nZandrel:G");
const segmenter = createSegmenter(lexicon);   // optional: reads the school part; same lexicon
const doc = deriveNameFormat(
  ["Quorrish, Zelvine", "Vantrell, Oramie - Zandrel", "Ospindle, Talwyn", "Quorrish, Oramie", "Vantrell, Talwyn"],
  { lexicon, segmenter },
);
doc.verdict;                    // "Last, First"
nameFormatOrder(doc.verdict);   // "surname-first": pass it as the document's declared order
doc.readings[1].name;           // "Vantrell, Oramie"
doc.readings[1].location;       // "Zandrel"

deriveNameFormat(["QUORRISH ZELVINE", "VANTRELL ORAMIE"], { lexicon }).verdict;  // "unknown": too few
readNameCell("QUORRISH ZELVINE", { lexicon }).order;                           // "surname-first:two-token"
```

判决是呼叫者对文件的声明; 将行组为 文档是呼叫者的.

宣布的命令胜过逗号;逗号只在没有宣布的情况下决定:

```ts
personName("Fennick, Orla", "given-first").nn2;  // "Orla<<Fennick": the declaration decides
personName("Fennick, Orla", "unknown").nn2;      // "Fennick<<Orla": the comma decides
```

在给定的第一个页面上,一个逗号在给定的第一个名称内比在某个名称内更经常被指点 一个倒置。 一个知道页面混合的呼叫者 `Surname, Given` 单元格为给定第一个 通行证 `unknown` 对于该页,所以逗号决定每个单元格. `deriveNameFormat` 报告此页面为 `unknown` (单位:千美元)`mixed`其中有许多人(6人中有3人) 单元格)和 `nameFormatOrder` 地图到 `unknown`; 单个流出单元格( 6个中的1个) 仍然 来源 `First Last`。 。 。 . `bun run names order <file>` 为文件打印相同的 名称单元格,每行1个。 规格是 `docs/NAME-NORMALIZATION.md`。 。 。 .

### 将拆分器对应于已公布的指纹

A 类 `Last, First` 打印自己的姓氏. `buildAnchorIndex` 从 打印其文件宣布其顺序, `anchoredSurname` 找到打印 同一名称的顺序 `primedVerdict` 说是否一个拆分者放置了边界 在这里。 分裂者是一个争论,所以故意错误的控制(`edgeOnlySplit`, (中文(简体) ), `compoundLessSplit`)显示栏可以失败. `unprimedTally` 按顺序猜测 扣留的申报,以及 `clearsUnprimedFloor` 将其平衡率与 `UNPRIMED_FLOOR`。 。 。 .

```ts
import {
  anchoredSurname, buildAnchorIndex, edgeOnlySplit, primedVerdict, splitPersonName,
} from "@finbheara/names/normalize";

const prints = [
  { name: "van der Quell, Pealling", declared: "Last, First" as const },
  { name: "Pealling van der Quell", declared: "First Last" as const },
];
const anchor = anchoredSurname(prints[1], buildAnchorIndex(prints));  // "vanderquell"
primedVerdict(prints[1], anchor, splitPersonName).verdict;             // "consistent"
primedVerdict(prints[1], anchor, edgeOnlySplit).verdict;               // "inconsistent"
```

### 两个名字如何关联

```ts
import {
  createGivenFamilyList, createNameIndex, createNameKinship, givenFamilyTable, nameKinship,
  personName,
} from "@finbheara/names/normalize";

nameKinship(personName("Kate Smith"), personName("Katherine Smith"));
// { relation: "candidate", via: ["given-family"], reason: "middles-equal", gateSafe: true }
nameKinship(personName("Mary Larson"), personName("Mary Conley-Larson")).via;  // ["surname-part"]
nameKinship(personName("Mary Larson"), personName("Mary Carlson")).reason;     // "surname-differs"
nameKinship(personName("Kate M Smith"), personName("Katherine Conley-Smith")).via;
// ["surname-part", "given-family", "middle-absent"]
nameKinship(personName("Connor Smith"), personName("Conor Smith")).via;       // ["given-variant"]
nameKinship(personName("Evie Smith"), personName("Genevieve Smith"));
// { relation: "candidate", via: ["given-family-not-gate"], reason: "middles-equal", gateSafe: false }
nameKinship(personName("Beth Smith"), personName("Bethany Smith"));   // the extended family list
// { relation: "candidate", via: ["given-maybe"], reason: "middles-equal", gateSafe: false }
nameKinship(personName("Grace Zumock"), personName("Ailbhe Grace Zumock"));  // a middle name used
// { relation: "candidate", via: ["given-middle"], reason: "middles-equal", gateSafe: false }

// four opt-in readings, each off by default: a suffix one side lacks, a run of initials,
// a hyphenated first name with its first half spelt another way, an Irish surname form
const wide = createNameKinship({
  suffixAbsent: true, initialRuns: true, joinedVariants: true, surnameForms: true,
});
wide(personName("Lena Zumock"), personName("Lena Zumock II")).via;      // ["suffix-absent"]
wide(personName("JR Zumock"), personName("Zumock, Joseph R.")).via;     // ["given-initials"]
wide(personName("Ann Marie Zumock"), personName("Zumock, Anne-Marie")).via;
// ["given-joined", "given-family"]
wide(personName("Lena Nolan"), personName("Ó Nualláin, Lena")).via;     // ["surname-form"]

// the given-name tolerance is a list of providers, asked in order
const tableOnly = createNameKinship({ given: [givenFamilyTable] });
tableOnly(personName("Beth Smith"), personName("Bethany Smith")).reason;  // "given-differs"
const common = createNameKinship({
  given: [givenFamilyTable, createGivenFamilyList({ maxTier: 1 })],  // common forms only
});
common(personName("Maggie Smith"), personName("Marjorie Smith")).reason;  // "given-differs"

const index = createNameIndex<number>("nn3");   // a NameMap with a tolerant lookup
index.set(personName("Mary Conley-Larson"), 1).set(personName("Mary Carlson"), 2);
index.get(personName("Mary Larson"));            // undefined: get stays exact
index.related(personName("Mary Larson"));        // [{ name: Conley-Larson<<Mary, value: 1, kinship: … }]
```

屏蔽一组记录(两个记录可以打印出一个名字),将记录放在屏蔽器中并取出 双对; 每对相关的对来一次, 不比较每对:

```ts
import { createNameBlocker, personName } from "@finbheara/names/normalize";

const blocker = createNameBlocker<string>();
blocker
  .add("row-1", personName("Mary Larson"))
  .add("row-2", personName("Mary Conley-Larson"))
  .add("row-3", personName("Mary Larson"))
  .add("row-4", personName("Mary Carlson"));
for (const { a, b, kinship } of blocker.pairs()) console.log(a.id, b.id, kinship.relation);
// row-1 row-3 same
// row-1 row-2 candidate
// row-2 row-3 candidate
```

`candidate` 它说两个指纹可能就是一个人. `via` 列表中 耐用对子,和 `gateSafe` 当其中任何一个都是一扇门时,是虚假的 自己承认吧.

A 类 `?` (或U+FFFD)在平面上是一个丢失的被捕获的字母. 关卡保持什么打印 保留,以及 `nameKinship` 读取每个 `?` 当指纹有分歧时 没有它:

```ts
import { lostLetterForm, nameKinship, personName } from "@finbheara/names/normalize";

nameKinship(personName("Zoë Bérard"), personName("Zo? B?rard"));
// { relation: "candidate", via: ["lost-letter"], reason: "middles-equal", gateSafe: false }
personName("Orlaith N? Varraigh").nn2;              // "NiVarraigh<<Orlaith": `N?` can only be Ní
lostLetterForm(personName("Zo? B?rard")).surname;   // "B?RARD": NN3's field, the `?` kept
```

一个名字读取西班牙语的方式(给定的名字、父亲的姓和母亲的姓)是选入的。 这里 默认关系表示 `different`, (中文(简体) ), `spanishNames: true` 阅读每个印刷品 每一个方式可能切割, 保持由粒子结合的化合物或 `y` 并且将完整形式与较短形式联系起来:

```ts
import { createNameIndex, createNameKinship, personName } from "@finbheara/names/normalize";

const spanish = createNameKinship({ spanishNames: true });
spanish(personName("Ana Inés Varrondo Quelmar"), personName("Inés Varrondo"));
// { relation: "candidate", via: ["surname-maternal", "given-middle", "spanish"],
//   reason: "middle-absent", gateSafe: false }
spanish(personName("Sofía Ostrevo Landar"), personName("SOFIA OSTREVO")).via;
// ["surname-maternal", "spanish"]
spanish(personName("Ailbhe Grace Zumock"), personName("Ailbhe Grace")).relation;
// "different": `Grace` is a given name, never the first surname
spanish(personName("Renata Ruelas y Terzán"), personName("Renata Ruelas")).relation;
// "different": `Ruelas y Terzán` is one surname

const index = createNameIndex<number>("nn3", { spanishNames: true });
index.set(personName("Ana Inés Varrondo Quelmar"), 1);
index.related(personName("Inés Varrondo")).map((m) => m.value);  // [1]
```

由OCR从扫描页读取的名字可能带有识别器混淆的格言:一个小写 `l` 资本 `I`, (中文(简体) ), `rn` 页:1 `m`。 。 。 . `ocrConfusion(a, b)` 比较两个字,回答: 运行它读作他们的可信任, `[]` 如果文字已经同意作为NN3读取,或 `null`它不产生任何结果,也不产生关键:`OCR_CONFUSABLES`页:1 读取 glyph, 包含大小写, 包没有设定阈值, 所以调用者计算 经营或拒绝一个班级本身. `createNameKinship({ ocrConfusables: true })` 读取字段 字段,关系会说 `different`,通过 `ocr-glyph` (从来不是安全的大门),和每 回答它用它携带的运行作为 `confusions`· ; `createNameIndex` 财务报告和审定财务报表 `createNameBlocker` 选择相同的选项, 因此每个匹配都带有相同的数组 :

```ts
import {
  OCR_CONFUSABLES, createNameIndex, createNameKinship, ocrConfusion, personName,
} from "@finbheara/names/normalize";

ocrConfusion("Quamby", "Quarnby");  // [{ class: "rn-m", a: "m", b: "rn", at: 3 }]
ocrConfusion("lvarra", "Ivarra");   // [{ class: "I-l", a: "l", b: "I", at: 0 }]
ocrConfusion("LVARRA", "IVARRA");   // null: a capital L is no capital I's confusable
ocrConfusion("Quarnby", "QUARNBY"); // []: equal as NN3 reads them

const ocr = createNameKinship({ ocrConfusables: true });
ocr(personName("Kate Quamby"), personName("Kate Quarnby"));
// { relation: "candidate", via: ["ocr-glyph"], reason: "middles-equal", gateSafe: false,
//   confusions: [{ class: "rn-m", a: "m", b: "rn", at: 3, field: "surname", index: 0 }] }
const noRn = createNameKinship({
  ocrConfusables: OCR_CONFUSABLES.filter((r) => r.class !== "rn-m"),
});
noRn(personName("Kate Quamby"), personName("Kate Quarnby")).relation;  // "different"

const index = createNameIndex<number>("nn3", { ocrConfusables: true });
index.set(personName("Kate Quarnby"), 1);
index.related(personName("Kate Quamby")).map((m) => m.kinship.confusions);  // [[{ class: "rn-m", … }]]
```

### 只有一个名字,一个有名的

```ts
import { createNameRoster, givenOnlyName, personName } from "@finbheara/names/normalize";

givenOnlyName("Lena").nn2;     // "<<Lena": the caller declares the print given-only
personName("Lena").isPerson(); // false: undeclared, one word is still refused
givenOnlyName("Lena Z.").nn2;  // "Z<<Lena": a trailing single letter is the surname initial

const roster = createNameRoster(
  ["Lena Zumock", "Mairéad Rervton", "Lena Brambleton", "Éilis Zumock"].map((p) => personName(p)),
);
roster.match(givenOnlyName("Mairead")); // { kind: "unique", name: Rervton<<Mairead }
roster.match(givenOnlyName("eilis"));   // { kind: "unique", name: Zumock<<Eilis }
roster.match(givenOnlyName("Lena"));    // { kind: "ambiguous", names: [Brambleton<<Lena, Zumock<<Lena] }
roster.match(givenOnlyName("Lena Z"));  // { kind: "unique", name: Zumock<<Lena }
roster.match(givenOnlyName("Orla"));    // { kind: "none", reason: "no-candidate" }
```

仅 `unique` 这是一个答案:名册从不挑选候选人。 打印匹配 以 `nameKinship`,其中缺少姓氏(`surname-absent`)或初始数据 (单位:千美元)`surname-initial`)不能排除一对夫妇出局,从来就没有门安全. 默认关系使用 指定名称的目录,所以 `Kate` 发现 `Katherine`; 通过 `{ kinship: createNameKinship({ given: [] }) }` 以匹配给定的名字。 回答没有 取决于设定的顺序.

### 其它语言的指定名称表

后面的桌子 后面的桌子 后面的桌子 `givenFamilyTable` 财务报告和审定财务报表 `givenFamilyList` 打印为 JSON, 给消费者 这不是JavaScript :

```sh
npx @finbheara/names tables given-name > given-name-tables.json   # or bunx
```

`--output json` 财务报告和审定财务报表 `--schema 1` 是默认的。 PRINTED表格是合同:a 只要软件包能保持它的形状 新的形状就是新的 计划,所以今天写的命令 继续工作。 表格中存储的文件是 不是它的一部分。 司马一是

```jsonc
{
  "$comment": [ /* how to read it */ ],
  "table": "given-name", "schema": 1,
  "variants":  { "CONNOR": ["CONOR"], … },        // canonical -> its other spellings
  "families":  { "CATHERINE": ["KATE", …], … },   // the curated gate tier: root -> forms
  "notAtGate": ["MEGAN", …],                      // forms a gate must not admit as forms
  "extended":  { "BETHANY": { "BETH": 1 }, … }    // root -> form -> tier (1 common .. 3 rare)
}
```

读它像图书馆一样 `$comment` 说:读出每个名字 拼写第一; 两个名称仅在共享根时关联, 一个表单满足 EveryY root it 坐在下面,没有什么是过渡性的(`EVIE` 开会 `EVE` 财务报告和审定财务报表 `EVA`,不分别满足 (其他部分)。 一个共享的根是 `given-family` 除非一个名字只作为 `notAtGate` 形式; 名字是根本身总是通过。 一个 `extended` 双层是稀有的 成员,根数为 1. 为避免比较每对,索引每个名称下 它的每个根 和比较在根, 从来没有一个根 每个名字.

## 密码和屏蔽键

```ts
import { doubleMetaphone } from "@finbheara/names/phonetic";
import { initialsBlock, metaphoneBlocks, personName, surnameBlock } from "@finbheara/names/normalize";

doubleMetaphone("SMITH");      // ["SM0", "XMT"]  primary, secondary
doubleMetaphone("KAVANAGH");   // ["KFNK", "KFNK"]

const n = personName("Moira O'Rervton");
surnameBlock(n.surnameKey());                     // "ORERVTON"  A-Z letters only
metaphoneBlocks(n.surnameKey());                  // ["ARRF"]
initialsBlock(n.givenFields()[0] ?? "", n.surnameKey());  // "MO"
```

`doubleMetaphone` 普通口音密钥:印刷名和转写口语 语言被问到同样的问题。 三个块键桶名值 比较和决定无;每个答案 `null` (或 `[]`无所事事的地方 桶装上,所以一个自相残杀 永远不能把空心.

### 作为数据库列的名称

```ts
import { NAME_COLUMNS, nameColumns, personName } from "@finbheara/names/normalize";

NAME_COLUMNS;  // ["nn0", …, "nn4", "surname_key", "given_key", "blk_surname", "blk_initials",
               //  "blk_metaphone", "blk_metaphone_alt"]
nameColumns(personName("Moira O'Rervton"));
// { nn0: "Moira O'Rervton", …, nn3: "ORERVTON<<MOIRA", surname_key: "ORERVTON",
//   given_key: "MOIRA", blk_surname: "ORERVTON", blk_initials: "MO", blk_metaphone: "ARRF", … }
```

每个密钥一个编码器一个存储索引,不依赖数据库。 级别栏 位点 `createNameMap` 将名称存档于, `null` 对于一个没有名字的指纹, 因此,一个级别上的地图检索就是一个列上的一等.

## 词典

```ts
import { Lexicon } from "@finbheara/names/lexicon";

const lex = Lexicon.default();              // the committed names.txt, parsed on first use
lex.getNameFlags("Murphy");                 // "LT": a surname, and a tradename
lex.getNameFlags("New York");               // "BG": a multi-word place
lex.matchBigramContinuations("New");        // [["south","wales"], ["york","city"], ..., ["york"], ...]
lex.displaySpelling("MACDONALD");           // "MacDonald"

Lexicon.load("./my-names.txt");             // your own file, same format (Node and Bun)
Lexicon.fromText("Aoife:F\nKowalski:L6\n");
```

### 名称.txt

每行一条, `Name:FLAGS`。 。 。 . `#` 开始评论。 没有旗帜的一行是女性 名称。 旗帜对大小写有敏感认识并结合(`Kelly:AF`, (中文(简体) ), `New York:BG`) (中文(简体) ).

| 旗帜 | 含义 |
| --- | --- |
| `F` `M` `N` | 女性 / 男性 / 性别中性名称 |
| `L` | 姓氏 |
| `A` | 含糊不清:既被视为一个给定的名字,又被视为一个姓氏 |
| `G` | 地点 |
| `T` | 商品名称:学校或教师 |
| `C` | 概念词 (`River`(中文(简体) ) |
| `B` | 多词条目( bigram 或 三相) |
| `S` | 一种已知的字型,保存所以被识别 |
| `X` | 从显示器的回程检查中排除 |
| `D` | 指定名称 diminutive table holds (`Kate:FD`);一个标记,像 `S` 财务报告和审定财务报表 `X` |

数字后 `L` 或者说 `A` 是一个 **传统脚注**数字 : `1` 亚美尼亚人, `2` 日耳曼语, `3` 伊比利亚人, `4` 爱尔兰人/加利克人, `5` 北欧, `6` 斯拉夫语( O)`Kowalski:L6`) (中文(简体) ). 一个索引是 永久发行;新的传统取下一份免费索引.

## 分类一个短语

```ts
import { phraseClassifier } from "@finbheara/names/classifier";

const pc = phraseClassifier();               // over the committed lexicon
pc.classifyNameNormalized("Quorrish Academy of Irish Dance");
// { scores: { person: 0.00, school: 1.00, location: 0.00 }, confidence: 1.00, category: "school" }
pc.segment("Mary Kate O Trurane Quorrish Academy");
// { type: "PS", person: ["Mary","Kate","O","Trurane"], school: ["Quorrish","Academy"], boundary: 4, ... }
```

一个后勤后退分级器和一个分级器 超过训练有素的重量和开花过滤器 公开姓名和地点名单`data/bloom/MANIFEST.json`) (中文(简体) ). 它是为 **多词** 短语; 对于单个符号,请询问词典.

宣布名称顺序的平面图( E)`given-first` 或者说 `surname-first`告诉 分类器是这样,然后分类器读取其单元格的重量只安装在 宣布该命令的文件。 在姓氏第一页,名称栏中的逗号 将姓氏与给定姓名区分开来:

```ts
pc.getNameCategory(cell, "surname-first"); // the order the document declares
pc.getNameCategory(cell);                  // no order: the same as "unknown"
```

通过文档宣布的命令, 永远不要猜测: 命令读取单元格本身 (单位:千美元)`inferNameOrder`)不是一个声明,所以它不是对分类器的输入. 与 没有命令,或者 `unknown`答案正是没有争论的答案. `classifyName`, (中文(简体) ), `classifyNameNormalized`, (中文(简体) ), `getNameCategory`, (中文(简体) ), `classifyBoundary` 编辑 `is…` 测试(之后) `threshold`拿着 垃圾拒绝和地点规则的答案 每一个命令下首先.

模特总是从人、学校或地方挑一个 无此内容的文本( 页 footers,标题)可以在前面声明;整个短语匹配忽略大小写, 间距和分数, 分数为零, 分数为零 :

```ts
const pc = phraseClassifier(undefined, { garbageVocab: ["Results are provisional (c)"] });
pc.classifyNameNormalized("RESULTS ARE PROVISIONAL (C)");
// { scores: { person: 0, school: 0, location: 0 }, confidence: 0, category: "none" }
```

## 测量名称流

```sh
npx names-census < names.txt-or.jsonl           # one name per line, or JSON lines
npx names-census --field=name --order-field=order --classify --limit=50 < rows.jsonl
```

```ts
import { createNameCensus } from "@finbheara/names/measure";

const census = createNameCensus();
for (const row of rows) census.add(row.name, row.order);
const report = census.report();
report.unknownTokens;  // words no lexicon entry knows, most printed first, with examples
report.unknownPairs;   // adjacent unknown words: candidate multi-word entries
report.refused;        // refusals by rule
```

未知的词是候选人 `names.txt` 增加数。 这几乎就是解决 每误读.

## 捐款

见 [捐款额](https://npmcn.com/package/%40finbheara/names/CONTRIBUTING.md): 如何添加名称,门,分类器 方法和版本.

## 许可证

麻省理工学院Finbheata系统。 开花桌由第三方名单组成 来源在 `data/bloom/MANIFEST.json`。 。 。 .

## 常见问题

### @finbheara/names 是什么？

个人、学校和地名、姓氏-粒子词汇、分类词和人名正常化词典

### 如何安装 @finbheara/names？

在项目目录运行 npm install @finbheara/names，或使用 pnpm add / yarn add / bun add。它还提供命令行工具 names、names-census，可以用 npx names 直接运行。

### @finbheara/names 支持 TypeScript 吗？

支持。包内自带 TypeScript 类型声明（package\.json 声明了 types 入口），安装后即可获得类型提示，无需再安装 @types 包。

### @finbheara/names 支持 ESM 还是 CommonJS？

以 ES Module 形式发布，推荐使用 import 引入。在 CommonJS 项目中，Node\.js 20\.19\+ / 22\.12\+ 可以直接 require\(\) 不含顶层 await 的 ES Module，更早的版本需要改用动态 import\(\)。

### @finbheara/names 需要什么版本的 Node\.js？

package\.json 的 engines 字段要求 Node\.js \>=22\.3。版本不符时 npm 默认只给出警告，开启 engine-strict 后会拒绝安装。

### @finbheara/names 可以商用吗？

@finbheara/names 使用 MIT 许可。宽松许可：允许商业使用、修改和再分发，通常只需在分发时保留原版权与许可声明。以上为概括，不构成法律意见，请以许可原文为准。

### @finbheara/names 的下载量有多少？

根据 npm 官方下载统计，@finbheara/names 在 2026/10/15 – 2026/11/13 这 30 天内被下载 3,357 次，日均约 112 次。下载量会把 CI 构建、镜像同步和作为其他包依赖的安装一并计入，适合横向比较热度，不能直接等同于使用人数。

### @finbheara/names 还在维护吗？

最新版本 0\.31\.0 发布于 2026/11/07（7 天前）；至今共发布 34 个版本，其中过去 12 个月发布了 34 个；首次发布于 2026/10/01。发布频率只是参考信号：功能稳定的工具可能很少需要更新，建议结合源码仓库的 issue 和提交记录判断。

