给定2个字符串,如何计算变化(插入、删除、替换)?【levenshtein distance 算法】
给定2个字符,计算字符串发生了那些变化(插入、删除、替换)
import { insert, remove, update } from "ramda";
// 计算差异度
export function levenshteinDistance<T = any>(a: T[],b: T[],compose: (a: T, b: T) => boolean = (a, b) => a === b
): number {return levenshteinDistanceMatrix(a, b, compose)[b.length][a.length];
}
// 计算差异矩阵,详见算法levenshtein distance
export function levenshteinDistanceMatrix<T = any>(a: T[],b: T[],compose: (a: T, b: T) => boolean = (a, b) => a === b
): number[][] {const distanceMatrix = Array(b.length + 1).fill(null).map(() => Array(a.length + 1).fill(null));for (let i = 0; i <= a.length; i += 1) {distanceMatrix[0][i] = i;}for (let j = 0; j <= b.length; j += 1) {distanceMatrix[j][0] = j;}for (let j = 1; j <= b.length; j += 1) {for (let i = 1; i <= a.length; i += 1) {const indicator = compose(a[i - 1],b[j - 1])? 0: 1;const min = Math.min(distanceMatrix[j][i - 1] + 1,distanceMatrix[j - 1][i] + 1,distanceMatrix[j - 1][i - 1] + indicator);distanceMatrix[j][i] = min;}}return distanceMatrix;
}
// 字符串变化类型
export enum LevenshteinOperatorType {// 删除deletion,// 插入insertion,// 替换substitution
}
// 删除数据结构
export interface LevenshteinDeletion<T = any> {type: LevenshteinOperatorType.deletion;index: number;value: T;
}
// 插入数据结构
export interface LevenshteinInsertion<T = any> {type: LevenshteinOperatorType.insertion;index: number;value: T;
}
// 替换数据结构
export interface LevenshteinSubstitution<T = any> {type: LevenshteinOperatorType.substitution;index: number;value: {old: T;new: T;};
}export type LevenshteinOperator<T = any> =| LevenshteinDeletion<T>| LevenshteinInsertion<T>| LevenshteinSubstitution<T>;
//是否删除
export function isLevenshteinDeletion<T = any>(val: LevenshteinOperator<T>
): val is LevenshteinDeletion<T> {return val.type === LevenshteinOperatorType.deletion;
}
// 是否插入
export function isLevenshteinInsertion<T = any>(val: LevenshteinOperator<T>
): val is LevenshteinInsertion<T> {return val.type === LevenshteinOperatorType.insertion;
}
// 是否替换
export function isLevenshteinSubstitution<T = any>(val: LevenshteinOperator<T>
): val is LevenshteinSubstitution<T> {return val.type === LevenshteinOperatorType.substitution;
}
// 默认最大值
const max = 9999999999;
export function levenshteinOperators<T = any>(a: T[],b: T[],compose: (a: T, b: T) => boolean = (a, b) => a === b
): LevenshteinOperator<T>[] {const res = levenshteinDistanceMatrix<T>(a, b, compose);// const dd = res.map(col => `|${col.join("|")}|`);// console.log(`${dd.join("\n")}`);// 求最小值坐标let i = b.length; // 行let j = a.length; //列let copy = a;let operators: LevenshteinOperator<T>[] = [];while (i > 0 || j > 0) {let deletion = max,insertion = max,substitution = max;const indicator = res[i][j];if (j > 0) {deletion = res[i][j - 1];}if (i > 0) {insertion = res[i - 1][j];}if (i > 0 && j > 0) {substitution = res[i - 1][j - 1];}const min = Math.min(deletion, insertion, substitution);if (min === insertion) {if (min !== indicator) {operators.push({type: LevenshteinOperatorType.insertion,value: b[i - 1],index: j - 1});}i -= 1;} else if (min === substitution) {if (min !== indicator) {operators.push({type: LevenshteinOperatorType.substitution,value: { old: a[j - 1], new: b[i - 1] },index: j - 1});}i -= 1;j -= 1;} else if (min === deletion) {if (min !== indicator) {operators.push({type: LevenshteinOperatorType.deletion,value: a[j - 1],index: j - 1});}j -= 1;}}return operators;
}
// 根据操作符,生成目标字符串
export function levenshteinTest<T>(a: T[],operators: LevenshteinOperator<T>[]
) {operators.map(opt => {if (isLevenshteinDeletion(opt)) {a = remove(opt.index, 1, a);}if (isLevenshteinInsertion(opt)) {a = insert(opt.index, opt.value, a);}if (isLevenshteinSubstitution(opt)) {a = update(opt.index, opt.value.new, a);}});return a;
}
复制代码
import { expect } from "chai";
import {levenshteinOperators,isLevenshteinSubstitution
} from "./levenshteinDistance";const a = `let item = 2;`;
const b = `let item = 3;`;
const ops = levenshteinOperators(a.split(""), b.split(""));describe("", () => {it("", () => {// 操作步骤长度为1expect(ops.length).equal(1);// 是替换操作符expect(isLevenshteinSubstitution(ops[0])).equal(true);// 将2替换为3expect((ops[0] as LevenshteinSubstitution).value.old).equal("2");expect((ops[0] as LevenshteinSubstitution).value.new).equal("3");});
});
复制代码
例子
levenshteinDistance
0 | 1 | 2 | 3 | 4 | 5 |
---|---|---|---|---|---|
1 | 【2】插入112 | 2 | 3 | 4 | 5 |
2 | 【2】插入, | 2 | 3 | 4 | 5 |
3 | 【3】插入223 | 3 | 3 | 4 | 5 |
4 | 【4】插入, | 4 | 4 | 4 | 5 |
5 | 【4】不变let | 5 | 5 | 5 | 5 |
6 | 5 | 【4】不变item | 5 | 6 | 6 |
7 | 6 | 5 | 【4】不变= | 5 | 6 |
8 | 7 | 6 | 5 | 【5】替换233->2 | 6 |
9 | 8 | 7 | 6 | 6 | 【5】不变; |
const old = "let item = 233;";
const newStr = "112,223,let item = 2;";
给定2个字符串,如何计算变化(插入、删除、替换)?【levenshtein distance 算法】相关推荐
- 字符串相似度算法——Levenshtein Distance算法
Levenshtein Distance 算法,又叫 Edit Distance 算法,是指两个字符串之间,由一个转成另一个所需的最少编辑操作次数.许可的编辑操作包括将一个字符替换成另一个字符,插入一 ...
- 字符串操作:插入,替换,填充及移除
字符串操作系列 本次涉及插入,替换,移除和填充几个操作. 1.插入(Insert) Insert(int startIndex,string value) :用于在一个字符串中的指定起始索引处插入另外 ...
- 可变字符串 插入,删除,替换,赋值
NSString *str=@"welcome to oc";//字符串常量不能放在可变字符串中,应该放在不可变的字符串中 mustr=[NSMutableString strin ...
- 0202插入删除-算法第四版红黑树-红黑树-数据结构和算法(Java)
文章目录 4 插入 4.1 序 4.2 向单个2-结点插入新键 4.3 向树底部的2-结点插入新键 4.4 向一棵双键树(3-结点)中插入新键 4.5 颜色调整 4.6 根结点总是黑色 4.7 向树底 ...
- python列表(list)+索引切片+修改+插入+删除+range函数生成整数列表对象
python列表(list)+索引切片+修改+插入+删除+range函数生成整数列表对象 列表(list)是什么? 列表是Python中内置有序.可变序列,列表的所有元素放在一对中括号"[] ...
- 进程句柄表初始化,扩展,插入删除句柄源码分析
一.为什么要有句柄 句柄是一个8字节的结构体,用途是指向内核对象.3环程序无法通过地址直接访问内核对象,所以需要用句柄来间接访问. 本文重点介绍句柄表,句柄本身则留到下一篇博客介绍.但因为接下来介绍句 ...
- 算法61---两个字符串的最小ASCII删除和【动态规划】
一.题目: 给定两个字符串s1, s2,找到使两个字符串相等所需删除字符的ASCII值的最小和. 示例 1: 输入: s1 = "sea", s2 = "eat" ...
- leetcode712. 两个字符串的最小ASCII删除和(动态规划)-Gogo
给定两个字符串s1, s2,找到使两个字符串相等所需删除字符的ASCII值的最小和. 示例 1: 输入: s1 = "sea", s2 = "eat" 输出: ...
- LeetCode 712. 两个字符串的最小ASCII删除和(DP,类似编辑距离)
1. 题目 给定两个字符串s1, s2,找到使两个字符串相等所需删除字符的ASCII值的最小和. 示例 1: 输入: s1 = "sea", s2 = "eat" ...
最新文章
- 在WebStorm里面搜索文件中出现的中文字符
- ORACLE ERP 的前世今生(5)
- linux Rootkit:x86与ARM的内联内核函数Hooking
- 关于 \8 为56问题解答
- Vscode解决Setting.json报警告:Problems loading reference ... Unable to load schema from ...
- javascript获取asp.net后台代码的方法
- Android之ndk之gdb调试
- Larbin源代码分析[6]LARBIN中线程处理类
- Java学习笔记-正则表达式的模式匹配
- 深圳大学计算机考研复习资料百度云,深圳大学(专业学位)计算机技术研究生考试科目和考研参考书目...
- [转载] python json 编码(dump/dumps:字典转化为json)、解码(load/loads:json转化为字典)
- 【三维路径规划】基于matlab改进差分算法多无人机协同三维路径规划【含Matlab源码 169期】
- win7+VS2008安装boost
- 数据库表文档生成工具screw (螺丝钉)
- 学编程考计算机二级,如何通过计算机一、二级考试?方法很重要,过来人的经验告诉你...
- 软件首次亮相前超级账本技术升温
- redis之十五(游标迭代器(过滤器)——Scan)
- #第七章 双波不干涉理论 ​一、双波不干涉理论的分级方法
- Unity接入Google登录
- MultipartFile 转换为File
热门文章
- 计算机控制系统的理论,计算机控制系统理论基础.pptx
- Golang unsafe.Pointer指针
- 崔巍 计算机考研怎么样,中国科学院大学研究生导师教师师资介绍简介-崔巍
- 亮剑.NET. 图解C#开发实战 在线阅读
- 一件有趣的事:用Python爬了自己的微信朋友圈
- bzoj1207(HNOI2004)打鼹鼠
- oracle 连接查询--内连接与外连接
- Windows Mobile与OPhone开发对比
- archsummit2017见闻和思考
- largest-rectangle-in-histogram