我试图在字符串中进行搜索,但它有时会改变。 我将有一个csv的文本,用户应该只写一个文本。
例:(这是csv数据中的一个单元格)我想要杂货店/面包店/咖啡店/披萨店/汉堡店
,(这是用户输入)我渴望杂货店
因此,用户可以创建一个短语,如我想要杂货店或任何其他选项像上面,这取决于他是什么在一个音频文件收听。
但他决定写作而不是“想要”,“渴望”。
注意:用户不知道我的数据,因为他只有访问音频和他转录什么他听到取决于他的词汇。 我不能强迫他采取一种特定的方式或写一个特定的短语。
有一种方法可以让我比较用户的输入和我已经得到的数据,并使之成为有效的输入,因为这两者在一天结束时具有相同的意义。
我尝试使用if(data.includes(用户短语))
-->; 这给了我虚假的信息。
我在一个csv文件中的数据,我读取它们,它们在对象中,其中每组短语被分组到一个特定的键[短语类型],用户数据是一个普通的字符串。
我怎样才能比较两个字符串之间的部分。
---更新
我也试过levenshtein相似性。。。 但是,我得到的数字非常小,与用户输入的最相似的短语是0.18,我不能用这个方法,做一个截止数字,作为参考,来判断这是否是一个相似度。
在两句话之间进行比较确实是一个复杂的问题。 您想要做的是使用某种stringSimmilarity函数,它将返回一个介于0到1之间的值,该值表示这两个字符串有多相似。 我用这个:
function compareTwoStrings(first, second) {
first = first.replace(/\s+/g, '').toLowerCase();
second = second.replace(/\s+/g, '').toLowerCase();
if (!first.length && !second.length) return 1; // if both are empty strings
if (!first.length || !second.length) return 0; // if only one is empty string
if (first === second) return 1; // identical
if (first.length === 1 && second.length === 1) return 0; // both are 1-letter strings
if (first.length < 2 || second.length < 2) return 0; // if either is a 1-letter string
let firstBigrams = new Map();
for (let i = 0; i < first.length - 1; i++) {
const bigram = first.substring(i, i + 2);
const count = firstBigrams.has(bigram) ? firstBigrams.get(bigram) + 1 : 1;
firstBigrams.set(bigram, count);
}
let intersectionSize = 0;
for (let i = 0; i < second.length - 1; i++) {
const bigram = second.substring(i, i + 2);
const count = firstBigrams.has(bigram) ? firstBigrams.get(bigram) : 0;
if (count > 0) {
firstBigrams.set(bigram, count - 1);
intersectionSize++;
}
}
return (2.0 * intersectionSize) / (first.length + second.length - 2);
}
function findBestMatch(mainString, targetStrings) {
if (!areArgsValid(mainString, targetStrings)) throw new Error('Bad arguments: First argument should be a string, second should be an array of strings');
const ratings = [];
let bestMatchIndex = 0;
for (let i = 0; i < targetStrings.length; i++) {
const currentTargetString = targetStrings[i];
const currentRating = compareTwoStrings(mainString, currentTargetString);
ratings.push({ target: currentTargetString, rating: currentRating });
if (currentRating > ratings[bestMatchIndex].rating) {
bestMatchIndex = i;
}
}
const bestMatch = ratings[bestMatchIndex];
return { ratings, bestMatch, bestMatchIndex };
}
function areArgsValid(mainString, targetStrings) {
if (typeof mainString !== 'string') return false;
if (!Array.isArray(targetStrings)) return false;
if (!targetStrings.length) return false;
if (targetStrings.find(s => typeof s !== 'string')) return false;
return true;
}
让我们稍微细分一下:findBestMatch获得两个参数--一个字符串和一个字符串数组(在您的示例中是用户输入,以及带有字符串的csv)。 然后,它对数组中的每个字符串使用compareTwoStrings来计算它们的相似性。 它返回评级,最佳匹配和它的索引。 然后,您可以决定接受匹配的阈值。 在您的案例中--在用户输入和给定的csv行上运行findBestMatch函数--得分为0.28,没有那么接近。。。 但是如果你的csv短信可以是这样的:我想要杂货店
,我想要面包店
等等,那么分数将是0.65--这更容易接受。
如果您愿意使用第三方工具,Elasticsearch将能够给出您正在寻找的结果。 它支持所谓的全文查询。 这意味着它将从您的用户输入中获取一个字符串,并与您在CSV中定义的所有现有文本行进行模糊比较。
当然,这将需要你a)安装Elasticsearch,b)提前提交所有现有的文本行。不过,它将允许你执行自由形式的搜索,并将结果按分数排序(即最接近的匹配优先)。
我已经链接了描述基本搜索功能的指南中的页面。 入门的第一章(“您知道,对于搜索”)也给出了端到端过程的非常清晰的演练。
https://www.elastic.co/guide/en/elasticsearch/guide/current/search.html