# @asmartbear/diff-merge 中文文档

规范地址：https://npmcn.com/package/%40asmartbear/diff-merge/

版本：2\.0\.0
npm 元数据更新时间：2026-06-16T01:21:07.095Z
中文译文更新时间：2026-11-08T11:26:31.431Z
软件包许可：MIT

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

原始 npm 页面：https://www.npmjs.com/package/%40asmartbear/diff-merge
原文对照：https://npmcn.com/package/%40asmartbear/diff-merge/?lang=original
项目主页：https://github.com/asmartbear/diff-merge#readme
源码仓库：https://github.com/asmartbear/diff-merge

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

- 包体积（解压后）：202 kB，7 个文件
- 模块格式：ES Module
- TypeScript 类型：包内自带
- Node.js 要求：\>=20
- 运行依赖：0 个
- 首次发布：2020-04-20T15:28:38.547Z
- 最新版本发布：2026-06-16T01:21:06.976Z
- 近 30 天下载量：1788（2026-10-07 至 2026-11-05，npm 官方下载统计）
- 已发布版本数：9（近 12 个月 1 个）

## 中文简介

文本和任意排列 diff 和合并、快速、多算法

## 安装

```sh
npm install @asmartbear/diff-merge
```

也可以使用：`pnpm add @asmartbear/diff-merge`、`yarn add @asmartbear/diff-merge`、`bun add @asmartbear/diff-merge`

## README

# 更好的 Diff 合并( M)

### 算法

-   **双向** -- 智能生成编辑脚本( 插入和删除) , 描述如何将一个数组转换成另一个数组 .
-   **三向合并** - 给一个共同的祖先版本,以及两个更新的版本,生成一个合并的结果,不仅合并了非相冲突的变化,而且精密地解决冲突.

### 特征

-   **致力于各种投入.** 按字符,单词,行,或任意符号化使用字符串(因此支持HTML等事物). 或使用与 **任意数组**。 。 。 .
-   **快点.** 大约比名人快四倍 `diff-merge-patch` [图书馆](https://github.com/google/diff-match-patch) (Neil Fraser,谷歌).
-   **优质成果.** 单位测试显示,编辑比基于流行的Myers-LCS方法的库更精准,如 `diff-merge-patch` (见下文).
-   **多种算法.** 因为不同的用例可能从不同的算法中受益. 其中包括一些小说.
-   **字迹.** 以 Typescript 写成,作为正则 Javascript 分发;包括 Typescript 声明.
-   **单位检验覆盖率100%.** 还有各种各样的角箱测试.

## 使用量

通过使用 [`npm`](https://www.npmjs.com/package/@asmartbear/diff-merge),或从 [吉图布](https://github.com/asmartbear/diff-merge)。 。 。 .

### `StringEngine` 最简单的引用,用于字符串

产生字符串之间的差异.

```javascript
import { StringEngine, DiffAlgorithm } from '@asmartbear/diff-merge'

/***** Differences by character *****/
prev = "This is a good test.";
next = "That is a test...";
eng = new StringEngine();
script = eng.getEditsByCharacter(prev, next);
console.log(script.toString());
// Th[is]{at} is a [good ]test.{..}
script.visitEditsForward( edit => {
    console.log("type:", edit.isEquality(), edit.isPureInsertion(), edit.isPureDeletion(), edit.isModification());
    console.log("prev:", edit.prev.getCopy().join(''));
    console.log("next:", edit.prev.getCopy().join(''));
});
// type: true, false, false, false
// prev: Th
// next: Th
// type: false, false, false, true
// prev: is
// next: at
// type: true, false, false, false
// prev:  is a 
// next:  is a 
// type: false, false, true, false
// prev: good
// next: 
// type: true, false, false, false
// prev: test.
// next: test.
// type: false, ftrue, false, false
// prev: 
// next: ..

/***** Differences for prose (by word) *****/
script = eng.getEditsByProse(prev, next);
console.log(script.toString());
// [This]{That} is a [good ]test.{..}

/***** Differences by other things *****/
script = eng.getEditsByLine(prev, next);
script = eng.getEditsByToken(prev, next, /</?[\w-]+[^>]*>/g);

/***** Engine options *****/
eng.opt_algorithm = DiffAlgorithm.SIMPLE;  // many times faster, but only basic diffs
eng.opt_algorithm = DiffAlgorithm.HENKEL;  // O(N), especially good with lines and code
eng.opt_shift_rightward = false;	 // faster, but diffs get confused with similar trailing chars
// There's more; see comments in the code.
```

### `Engine` -- 主类,用于不同数组

将上面的例子改为: `Engine` 改为 `StringEngine`启用 `getEdits()` 而不是上面的字符串指定。 编辑脚本是所使用对象的数组,而不是字符串.

### `Merge` -- 三向合并

这个算法假设已经计算出共享版本和两个新版本之间的差异. 这使得您可以使用任意的标志化和差异引擎选项.

新版本中的第一个叫"现状",第二个叫"应用". 虽然几乎总是合并是对称的,但有时会出现有角相冲突,或者有某些算法选项,需要打出平手. 在这种情况下,领会到"现状"

```typescript
import { StringEngine, Merge } from '@asmartbear/diff-merge'

orig = "This is a sentence that will be modified twice.";
ver1 = "That was a sentence which will be modified";
orig = "This is sentences that can't be stopped!";
eng = new StringEngine();
orig_to_ver1 = eng.getEditsByCharacter(orig, ver1);
orig_to_ver2 = eng.getEditsByCharacter(orig, ver2);
console.log(orig_to_ver1.toString());
console.log(orig_to_ver2.toString());
// Th[is i]{at wa}s a sentence [that]{which} will be modified[ twice.]
// This is [a ]sentence{s} that [will]{can't} be [modified twice.]{stopped!}

merge = new Merge<string>();
result = merge.merge3( orig_to_ver1, orig_to_ver2 );
console.log(result);
// That was sentences which can't be stopped!
/***** Notice: overlapping deletions and modifications are combined. *****/

merge.opt_combine_overlapping_inserts  // can keep both, merge, or keep just status quo
merge.opt_algorithm_combined_overlapping_inserts  // when inserts match, we de-duplicate
merge.opt_f_handle_deleted_insert      // callback when we delete an insert -- see below.
```

当一方的插入完全发生在从另一方删除的范围之内时,该插入被忽略. 例如,如果爱丽丝删除了一整段,而鲍勃纠正了该段内的一个打字,那么鲍勃的修改应该被遗忘. 这个 `opt_f_handle_deleted_insert` 允许用户随时定义回调函数。 例如,您可以在某个地方的用户界面中显示被丢弃的插入列表,以防需要找到重要的东西.

## 我们所说的"高质量差异"的例子

考虑这两个字符串,其中包含变化以及重复的词和短语:

```
   A: if the word order changes a lot of the time
   B: then changes in the word order are changes a lot of the time that we like
```

有多种方法来解释所发生的变化。 如果从语义角度选择更好的,结果对于人类来说(可能正在尝试去学习"发生的事情")更能理解,同时也会导致更好的合并(因为语义冲突被减少).

这个 `diff-merge-patch` 库,或任何其他 Myers-LCS 方法,将产生毫无意义的 diffs;这就是图书馆实际创建的 。 第一种是默认输出;第二种是经过其"语义"清理过程后进行. (这里) `[brackets]` 意思是"删除这个"和 `{curly}` "插入这个"的意思:

```
DMP1: [I]{then changes a lot o}f the {time are }word order changes {th}a[ lo]t [of]{we} [t]{s}h[e]{ould} [t]{l}I[m]{k}e
DMP2: [if th]{then changes a lot of the time ar}e word order changes [a lot of the tim]{that we should lik}e
```

相较于此库中的默认算法,一种小说中最长的子集(不是最长的子集!)方法:

```
THIS: [if ]the[ word order]{n} changes a lot of the time{ are word order changes that we should like}
```

另一个例子是,一个词被围绕一个小变化重新排序,我们的小说算法理解了这一点,但经典的DMP并没有,而是显示这个常用词被删除并重新插入:

```
   A: Will be slightly edited in the edited version
   B: Will be edited a little bit in the edited version
DMP1: Will be [sl]{ed}I[gh]t[ly ]ed{ a l}it{tl}e[d]{ bit} in the edited version.
DMP2: Will be [slightly edited]{edited a little bit} in the edited version.
THIS: Will be [slightly ]edited {a little bit }in the edited version.
```

另一处,我们把句子结尾处的改动解释得完美, Myers-LCS 打破:

```
   A: The quick brown fox jumps over the lazy dogs.
   B: These quickish browne fox jumps about the lacidasical dogs...right?
DMP2: The{se} quick{ish} brown{e} fox jumps [over]{about} the la[zy dogs.]{cidasical dogs...right?}"
THIS: The{se} quick{ish} brown{e} fox jumps {ab}o[ver]{ut} the la[zy]{cidasical} dogs.{..right?}
```

最后,一个长句,从实际的 [实例](https://link.springer.com/article/10.1007/s42803-019-00012-w) 从文献中,DMP1使变化变得一团糟,而DMP2则会产生大块的插入和删除,这些插入和删除错过了语义上的相近之处,并且与这种算法逐个字比较好得多(`WORD`)),并在此包含另一个算法,它从一个亨克尔通过到更好的组等块,然后使用默认算法来分析等分相间的片段,则更好(`BOTH`:

```
   A: with the boat train arriving, people talking loudly, chains being dropped, and the screws the beginning, and the steamer suddenly hooting
   B: with the boat train arriving; with people quarrelling outside the door; chains clanking; and the steamer giving those sudden stertorous snorts
DMP1: with the boat train arriving[,]{; with} people [t]{qu}a{rre}l[k]{l}ing [l]ou{tsi}d[ly,]{e the door;} chains [be]{clank}ing[ dropped,]{;} and the s[cr]{t}e[ws th]{am}e{r} [be]gi[nn]{v}ing[, and] th[e ]{o}s[t]e[amer] sudden[ly] [h]{stert}o{r}o[ti]{us s}n[g]{orts}
DMP2: with the boat train arriving[,]{; with} people [talk]{quarrell}ing [l]ou[dly, chains being dropped, and the screws the beginning, and the steamer suddenly hooting]{tside the door; chains clanking; and the steamer giving those sudden stertorous snorts}
THIS: with the boat train arriving[,]{; with} people [t]{qu}a{rre}l[k]{l}ing [l]ou{tsi}d[ly,]{e the door;} chains [be]{clank}ing[ dropped, and the screws the beginning,]{;} and the steamer {giving those }sudden[ly] [h]{stert}o{r}o{us snor}t[ing]{s}

WORD: with the boat train arriving[,]{; with} people [talking]{quarrelling} [loudly, chains being dropped, and]{outside} the [screws]{door;} [the]{chains} [beginning,]{clanking;} and the steamer [suddenly]{giving} [hooting]{those sudden stertorous snorts}
BOTH: with the boat train arriving[,]{; with} people [talking]{quarrelling} [loudly,]{outside the door;} chains [being dropped, and the screws the beginning,]{clanking;} and the steamer [suddenly]{giving} [hooting]{those sudden stertorous snorts}
```

## 捐款

这是一个仅限无害环境管理的TypeScript包;需要20+节点.

```bash
npm install
npm test           # vitest, all tests must pass
npm run typecheck  # tsc --noEmit
npm run lint       # biome check
npm run build      # tsc → dist/
npm run bench      # vitest bench (relative timing vs DMP)
```

#罗斯/README

## 常见问题

### @asmartbear/diff-merge 是什么？

文本和任意排列 diff 和合并、快速、多算法

### 如何安装 @asmartbear/diff-merge？

在项目目录运行 npm install @asmartbear/diff-merge，或使用 pnpm add / yarn add / bun add。

### @asmartbear/diff-merge 支持 TypeScript 吗？

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

### @asmartbear/diff-merge 支持 ESM 还是 CommonJS？

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

### @asmartbear/diff-merge 需要什么版本的 Node\.js？

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

### @asmartbear/diff-merge 可以商用吗？

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

### @asmartbear/diff-merge 的下载量有多少？

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

### @asmartbear/diff-merge 还在维护吗？

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

