java 字符串对齐_最佳字符串对齐的Java实现

java 字符串对齐

有一阵子,我使用了Levenshtein distance的Apache Commons lang StringUtils实现。 它实现了一些众所周知的技巧,通过仅挂接到两个数组而不是为备忘录表分配巨大的nxm表来使用较少的内存。 它还仅检查宽度为2 * k +1的“条带”,其中k是最大编辑次数。

在levenshtein的大多数实际用法中,您只关心一个字符串是否在另一个字符串的少量编辑(1、2、3)之内。 这避免了使levenstein变得“昂贵”的大部分n * m计算。 我们发现,在ak <= 3的情况下,具有这些技巧的levenshtein的速度比Jaro-Winkler distance快,后者是一种近似编辑距离计算,被创建为更快的近似值(这有很多原因)。

不幸的是,Apache Commons Lang实现仅计算Levenshtein,而不计算可能更有用的Damerau-Levenshtein距离 。 Levenshtein定义了编辑操作的插入,删除和替换。 Damerau变体将* transposition *添加到列表中,这对于我使用编辑距离的大多数位置都非常有用。 不幸的是,DL距离不是真正的度量标准,因为它不考虑三角形不等式,但是有很多应用不受此影响。 从该维基百科页面可以看到,“最佳字符串对齐”和DL距离之间经常会混淆。 实际上,OSA是一种更简单的算法,并且需要较少的簿记,因此运行时间可能略微更快。

我找不到任何使用我在Apache Commons Lang中看到的内存技巧和“条带化”技巧的OSA或DL实现。 因此,我使用这些技巧实现了自己的OSA。 在某些时候,我还将使用技巧来实现DL,并查看性能差异是什么:

这是Java中的OSA。 它是公共领域; 随意使用。 单元测试如下。 唯一的依赖关系是Guava-,但它只是前提条件类和文档注释,因此如果您愿意,可以轻松删除该依赖关系:

package com.github.steveash.util;import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.primitives.Shorts.checkedCast;
import static java.lang.Math.abs;
import static java.lang.Math.max;import java.util.Arrays;import com.google.common.annotations.VisibleForTesting;/*** Implementation of the OSA which is similar to the Damerau-Levenshtein in that it allows for transpositions to* count as a single edit distance, but is not a true metric and can over-estimate the cost because it disallows* substrings to edited more than once.  See wikipedia for more discussion on OSA vs DL* <p/>* See Algorithms on Strings, Trees and Sequences by Dan Gusfield for more information.* <p/>* This also has a set of local buffer implementations to avoid allocating new buffers each time, which might be* a premature optimization* <p/>* @author Steve Ash*/
public class OptimalStringAlignment {private static final int threadLocalBufferSize = 64;private static final ThreadLocal<short[]> costLocal = new ThreadLocal<short[]>() {@Overrideprotected short[] initialValue() {return new short[threadLocalBufferSize];}};private static final ThreadLocal<short[]> back1Local = new ThreadLocal<short[]>() {@Overrideprotected short[] initialValue() {return new short[threadLocalBufferSize];}};private static final ThreadLocal<short[]> back2Local = new ThreadLocal<short[]>() {@Overrideprotected short[] initialValue() {return new short[threadLocalBufferSize];}};public static int editDistance(CharSequence s, CharSequence t, int threshold) {checkNotNull(s, "cannot measure null strings");checkNotNull(t, "cannot measure null strings");checkArgument(threshold >= 0, "Threshold must not be negative");checkArgument(s.length() < Short.MAX_VALUE, "Cannot take edit distance of strings longer than 32k chars");checkArgument(t.length() < Short.MAX_VALUE, "Cannot take edit distance of strings longer than 32k chars");if (s.length() + 1 > threadLocalBufferSize || t.length() + 1 > threadLocalBufferSize)return editDistanceWithNewBuffers(s, t, checkedCast(threshold));short[] cost = costLocal.get();short[] back1 = back1Local.get();short[] back2 = back2Local.get();return editDistanceWithBuffers(s, t, checkedCast(threshold), back2, back1, cost);}@VisibleForTestingstatic int editDistanceWithNewBuffers(CharSequence s, CharSequence t, short threshold) {int slen = s.length();short[] back1 = new short[slen + 1];    // "up 1" row in tableshort[] back2 = new short[slen + 1];    // "up 2" row in tableshort[] cost = new short[slen + 1];     // "current cost"return editDistanceWithBuffers(s, t, threshold, back2, back1, cost);}private static int editDistanceWithBuffers(CharSequence s, CharSequence t, short threshold,short[] back2, short[] back1, short[] cost) {short slen = (short) s.length();short tlen = (short) t.length();// if one string is empty, the edit distance is necessarily the length of the otherif (slen == 0) {return tlen <= threshold ? tlen : -1;} else if (tlen == 0) {return slen <= threshold ? slen : -1;}// if lengths are different > k, then can't be within edit distanceif (abs(slen - tlen) > threshold)return -1;if (slen > tlen) {// swap the two strings to consume less memoryCharSequence tmp = s;s = t;t = tmp;slen = tlen;tlen = (short) t.length();}initMemoiseTables(threshold, back2, back1, cost, slen);for (short j = 1; j <= tlen; j++) {cost[0] = j; // j is the cost of inserting this many characters// stripe boundsint min = max(1, j - threshold);int max = min(slen, (short) (j + threshold));// at this iteration the left most entry is "too much" so reset itif (min > 1) {cost[min - 1] = Short.MAX_VALUE;}iterateOverStripe(s, t, j, cost, back1, back2, min, max);// swap our cost arrays to move on to the next "row"short[] tempCost = back2;back2 = back1;back1 = cost;cost = tempCost;}// after exit, the current cost is in back1// if back1[slen] > k then we exceeded, so return -1if (back1[slen] > threshold) {return -1;}return back1[slen];}private static void iterateOverStripe(CharSequence s, CharSequence t, short j,short[] cost, short[] back1, short[] back2, int min, int max) {// iterates over the stripefor (int i = min; i <= max; i++) {if (s.charAt(i - 1) == t.charAt(j - 1)) {cost[i] = back1[i - 1];} else {cost[i] = (short) (1 + min(cost[i - 1], back1[i], back1[i - 1]));}if (i >= 2 && j >= 2) {// possible transposition to check forif ((s.charAt(i - 2) == t.charAt(j - 1)) &&s.charAt(i - 1) == t.charAt(j - 2)) {cost[i] = min(cost[i], (short) (back2[i - 2] + 1));}}}}private static void initMemoiseTables(short threshold, short[] back2, short[] back1, short[] cost, short slen) {// initial "starting" values for inserting all the lettersshort boundary = (short) (min(slen, threshold) + 1);for (short i = 0; i < boundary; i++) {back1[i] = i;back2[i] = i;}// need to make sure that we don't read a default value when looking "up"Arrays.fill(back1, boundary, slen + 1, Short.MAX_VALUE);Arrays.fill(back2, boundary, slen + 1, Short.MAX_VALUE);Arrays.fill(cost, 0, slen + 1, Short.MAX_VALUE);}private static short min(short a, short b) {return (a <= b ? a : b);}private static short min(short a, short b, short c) {return min(a, min(b, c));}
}
import org.junit.Testimport static com.github.steveash.util.OptimalStringAlignment.editDistance/*** @author Steve Ash*/
class OptimalStringAlignmentTest {@Testpublic void shouldBeZeroForEqualStrings() throws Exception {assert 0 == editDistance("steve", "steve", 1)assert 0 == editDistance("steve", "steve", 0)assert 0 == editDistance("steve", "steve", 2)assert 0 == editDistance("steve", "steve", 100)assert 0 == editDistance("s", "s", 1)assert 0 == editDistance("s", "s", 0)assert 0 == editDistance("s", "s", 2)assert 0 == editDistance("s", "s", 100)assert 0 == editDistance("", "", 0)assert 0 == editDistance("", "", 1)assert 0 == editDistance("", "", 100)}@Testpublic void shouldBeOneForSingleOperation() throws Exception {def a = "steve";for (int i = 0; i < 5; i++) {assertOneOp(new StringBuilder(a).insert(i, 'f'), a)assertOneOp(new StringBuilder(a).deleteCharAt(i), a)def sb = new StringBuilder(a)sb.setCharAt(i, 'x' as char);assertOneOp(sb, a)if (i > 1) {sb = new StringBuilder(a)char t = sb.charAt(i - 1)sb.setCharAt(i - 1, sb.charAt(i))sb.setCharAt(i, t)println "comparing " + sb.toString() + " -> " + aassertOneOp(sb, a)}}}@Testpublic void shouldCountTransposeAsOne() throws Exception {assert 3 == editDistance("xxsteve", "steev", 4)assert 3 == editDistance("xxsteve", "steev", 3)assert 3 == editDistance("steev", "xxsteve", 4)assert 3 == editDistance("steev", "xxsteve", 3)assert -1 == editDistance("steev", "xxsteve", 2)assert 4 == editDistance("xxtseve", "steev", 4)assert 5 == editDistance("xxtsevezx", "steevxz", 5)assert 6 == editDistance("xxtsevezx", "steevxzpp", 6)assert 7 == editDistance("xxtsfevezx", "steevxzpp", 7)assert 4 == editDistance("xxtsf", "st", 7)assert 4 == editDistance("evezx", "eevxzpp", 7)assert 7 == editDistance("xxtsfevezx", "steevxzpp", 7)}@Testpublic void shouldCountLeadingCharacterTranspositionsAsOne() throws Exception {assert 1 == editDistance("rosa", "orsa", 2)}private void assertOneOp(CharSequence a, CharSequence b) {assert 1 == editDistance(a, b, 1)assert 1 == editDistance(b, a, 1)assert 1 == editDistance(a, b, 2)assert 1 == editDistance(b, a, 2)}@Testpublic void shouldShortCutWhenSpecialCase() throws Exception {assert 1 == editDistance("s", "", 1)assert 1 == editDistance("", "s", 1)assert -1 == editDistance("s", "", 0)assert -1 == editDistance("", "s", 0)assert -1 == editDistance("st", "", 1)assert -1 == editDistance("", "st", 1)assert -1 == editDistance("steve", "ste", 0)assert -1 == editDistance("ste", "steve", 0)assert -1 == editDistance("stev", "steve", 0)assert -1 == editDistance("ste", "steve", 1)assert -1 == editDistance("steve", "ste", 1)assert 1 == editDistance("steve", "stev", 1)assert 1 == editDistance("stev", "steve", 1)}
}

参考:来自我们的JCG合作伙伴史蒂夫·阿什(Steve Ash)的Java实现最佳字符串对齐 ,该博客来自Many Cups of Coffee博客。

翻译自: https://www.javacodegeeks.com/2013/11/java-implementation-of-optimal-string-alignment.html

java 字符串对齐

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/346035.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

zabbix可以监控什么php,zabbix监控php

通过启用php-fpm的status页面&#xff0c;使用zabbix来获取各数据参数以达到监控php-fpm性能状态php-fpm配置配置文件php-fpm.confpm.status_path /fpmstatusping.path /fpmpingping.response pongnginx配置在配置的server内添加locationlocation ~ ^/(fpmstatus|fpmping) {…

建立无服务器的“ Hello World”功能

无服务器 &#xff0c;功能即服务&#xff08;FaaS&#xff09;或仅具有云功能&#xff0c;就可以编写将在云中运行的代码。 您可以使用多种不同的语言&#xff08;例如JavaScript&#xff08;Node.js&#xff09;&#xff0c;Swift&#xff0c;Python&#xff0c;Java&#xf…

oracle 10g 分区管理,Oracle 10g分区表的自动维护

Oracle 10g分区表不支持自动化管理&#xff0c;一般都要手动创建分区&#xff0c;手动删除。今天给大家带来了一个自动化管理表空间的脚本。本脚本主要由3个部分组成&#xff1a;sys_ConfigTable.sql、sys_pro_AddAndDropPartition.sql、sys_pro_MergeTable.sql1、sys_ConfigTa…

Oracle12如何重装,Oracle怎么重新安装?

实现方法&#xff1a;1、 开始&#xff0d;&#xff1e;设置&#xff0d;&#xff1e;控制面板&#xff0d;&#xff1e;管理工具&#xff0d;&#xff1e;服务 停止所有Oracle服务。2、 开始&#xff0d;&#xff1e;程序&#xff0d;&#xff1e;Oracle - OraHome81&#xff…

java实现metro风格_Metro风格的Java组合框(JMetro)–重新介绍

java实现metro风格我上一篇关于JMetro的文章–我的都市风格的Java皮肤&#xff08;或外观&#xff09;是关于日历选择器控件的 。 我本打算使用Tom Eugelink不错的日历选择器&#xff0c;但当时我了解到它是由Oracle创建并随Java 8一起提供的&#xff0c;因此出于时间的考虑&am…

Istio的网络API解释了

Istio 1.0版附带一个网络API&#xff0c;该API包含许多功能并涵盖了各种情况。 联网API在最近几个月中得到了发展&#xff0c;并且可能无法立即说明。 该API的概念和构建块是什么&#xff0c;以及如何使用各个Istio资源类型来通过我们的服务网格路由流量&#xff1f; 尽管文档…

toad查看oracle的plsql包,Oracle logminer 分析redo log(TOAD与PLSQL)

Oracle logminer 分析redo logOracle 11g r2 RAC centos 6.5设置时间格式select to_char(sysdate,yyyy-mm-dd hh24:mi:ss) date_format from dual ;查看数据库是否开启补全日志功能selectSUPPLEMENTAL_LOG_DATA_MIN,SUPPLEMENTAL_LOG_DATA_PK,SUPPLEMENTAL_LOG_DATA_UI,SUPPLEM…

php里面的mark,PHP CommonMarkCQL 用法 手册 | 示例代码

简介CommonMark Query Language is a DSL for describing how to travel through a CommonMark Node tree implemented as a parser and compiler for a small set of instructions, and a virtual machine for executing those instructions.Paths:In its most simplistic for…

spring 面向接口编程_Spring面向方面的编程

spring 面向接口编程介绍 在理想的面向对象系统中&#xff0c;我们希望将每个对象设计为执行一项特定任务。 但是&#xff0c;除了执行其主要任务之外&#xff0c;对象还执行被动任务&#xff0c;例如日志记录&#xff0c;事务&#xff0c;安全性&#xff0c;缓存等。这些被动活…

Nutshell中的Java 8语言功能-第2部分

编者注&#xff1a;您也可以在此处检查Part-1。 嗨&#xff0c;朋友们&#xff0c;这是简明系列的Java 8语言功能的第2部分。 在这里&#xff0c;我们将讨论Java 8的以下功能&#xff1a; 接口中的静态方法 流 1.接口中的静态方法 什么是静态方法&#xff1f; 静态方法是属…

概率

概率 概率质量函数&#xff08;probability mass function, PMF&#xff09;针对的是离散变量 常见的离散随机变量分布的PMF函数&#xff1a;伯努利分布&#xff0c;二项分布&#xff0c;泊松分布。 概率密度函数&#xff08;probability density function, PDF&#xff09;针…

oracle impdp导入时卡住,Oracle:impdp导入等待statement suspended, wait error to be cleared

用数据泵impdp往开发数据库导数据&#xff0c;但导入到INDEX时感觉卡住不动了Processing object type SCHEMA_EXPORT/TABLE/INDEX/INDEX----查看状态&#xff0c;Completed Objects: 33一直没有变化。Import> statusJob: SYS_IMPORT_FULL_01Operation: IMPORTMode: FULLStat…

梯度下降法、最速下降法

梯度下降法 最优化问题是求解函数极值的问题&#xff0c;包括极大值和极小值。相信所有的读者对这个问题都不陌生&#xff0c;在初中时我们就学会了求解二次函数的极值&#xff08;抛物线的顶点&#xff09;&#xff0c;高中时学习了幂函数&#xff0c;指数函数&#xff0c;对…

php ajax 表格编辑,php ajax表格实时编辑 PHP Ajax实现表格实时编辑

想了解PHP Ajax实现表格实时编辑的相关内容吗&#xff0c;佛祖的腿毛在本文为您仔细讲解php ajax表格实时编辑的相关知识和一些Code实例&#xff0c;欢迎阅读和指正&#xff0c;我们先划重点&#xff1a;php,ajax表格实时编辑,ajax实现表格编辑&#xff0c;下面大家一起来学习吧…

jpa和hibernate_使用JPA和Hibernate有效删除数据

jpa和hibernate您可能会遇到必须对关系数据库中存储的大量数据集执行批量删除的情况。 如果您将JPA与Hibernate一起用作基础OR映射器&#xff0c;则可以尝试通过以下方式调用EntityManager的remove&#xff08;&#xff09;方法&#xff1a; public void removeById(long id) …

超越函数

代数数 在数论中&#xff0c;超越数是指任何一个不是代数数的数字&#xff08;通常它是复数&#xff09;。它满足以下条件——只要它不是任何一个整系数代数方程的根&#xff0c;它即是超越数。最著名的超越数是e以及π。 超越数 超越数的例子 所有超越数构成的集是一个不可数…

无服务器-仅仅是构建现代应用程序的一种方法?

如果搜索“无服务器”&#xff0c;则会发现无服务器是构建现代应用程序的一种新的流行方式。 无服务器真的是新的吗&#xff1f; 无服务器是指您无需担心服务器的概念-无需置备&#xff0c;部署和维护服务器。 显然有服务器&#xff0c;但是您无需考虑或担心它们&#xff0c;运…

linux查看用户的操作记录,Linux下查看用户登陆后的操作记录

Linux下查看用户登陆后的操作记录  在linux系统的环境下&#xff0c;不管是root用户还是其它的用户只有登陆系统后用进入操作我们都可以通过命令history来查看历史记录&#xff0c;可是假如一台 服务器多人登陆&#xff0c;一天因为某人误操作了删除了重要的数据。这时候通过…

只需5分钟即可启动并运行分层架构:: Spring Boot第1部分

这是一个分为两部分的系列&#xff0c;其中我将展示如何使用Spring Boot创建分层架构。 什么是分层体系结构&#xff1a;简而言之&#xff0c;当我们构建企业应用程序时&#xff0c;我们维护不同的层以封装特定于层的逻辑&#xff0c;这样就不会溢出到另一层。 当我们考虑企业…