Greasy Fork is available in English.

string-overlap-matching-degree

计算字符串重叠/匹配度计算

2024-08-18 기준 버전입니다. 최신 버전을 확인하세요.

이 스크립트는 직접 설치하는 용도가 아닙니다. 다른 스크립트에서 메타 지시문 // @require https://update.greatest.deepsurf.us/scripts/501646/1429884/string-overlap-matching-degree.js을(를) 사용하여 포함하는 라이브러리입니다.

  1. /**
  2. * 重叠匹配度
  3. * @author: zhuangjie
  4. * @date: 2024-07-23
  5. */
  6. function overlapMatchingDegreeForObjectArray(keyword = "", objArr = [], fun = (obj) => [], {sort = "desc", onlyHasScope = false, scopeForObjArrContainer} = {}) {
  7. const scopeForData = objArr.map(item => overlapMatchingDegree(keyword, fun(item), sort));
  8. // scope与 objArr 同步排序
  9. sortAndSync(scopeForData, objArr, sort);
  10. if (Array.isArray(scopeForObjArrContainer)) {
  11. scopeForObjArrContainer.push(...scopeForData);
  12. }
  13.  
  14. return onlyHasScope ? objArr.filter((_, index) => scopeForData[index] !== 0) : objArr;
  15. }
  16. /**
  17. * 计算匹配度外层封装工具
  18. * @param {string} keyword - 匹配字符串1
  19. * @param {Object | Arrayy} topicWeighs - 匹配字符串2与它的权重
  20. * @returns {number} 匹配度分数
  21. */
  22. function overlapMatchingDegree(keyword, topicWeighs = {}, sort = "desc") {
  23. if (Array.isArray(topicWeighs)) {
  24. const weightMultiplier = sort === "asc" ? 1 : -1;
  25. topicWeighs = Object.fromEntries(topicWeighs.map((topic, index) => [topic, (index + 1) * weightMultiplier]));
  26. }
  27. return Object.keys(topicWeighs).reduce((totalScore, topic) => {
  28. const currentScore = topicWeighs[topic];
  29. const overlapLengthBlocksMap = findOverlapBlocks(keyword, topic);
  30. return totalScore + Object.entries(overlapLengthBlocksMap).reduce((sum, [length, blocks]) => {
  31. return sum + blocks.length * Math.pow(currentScore, Number(length));
  32. }, 0);
  33. }, 0);
  34. }
  35. /**
  36. * 查找重叠匹配块(入口函数)
  37. * @param {*} str1
  38. * @param {*} str2
  39. * @returns 返回重叠块 如:{"2": ["好用","推荐"],"3": ["好用推荐"]}
  40. * 算法核心思想:
  41. * -----------------------------------------------------
  42. * sumatrapdf* | sumatrapdf* | sumatrapdf*
  43. * pdf- | pdf- | pdf-
  44. * ------------------------------------------------------
  45. */
  46. function findOverlapBlocks(str1 = "", str2 = "") {
  47. const alignmentHub = {};
  48. const str1Len = str1.length;
  49. const str2Len = str2.length;
  50. const minLen = Math.min(str1Len, str2Len);
  51.  
  52. for (let offset = 1 - str2Len; offset < str1Len; offset++) {
  53. const start = Math.max(0, offset);
  54. const end = Math.min(str1Len, str2Len + offset);
  55. const overlapStr1 = str1.slice(start, end);
  56. const overlapStr2 = str2.slice(start - offset, end - offset);
  57.  
  58. const alignmentContent = alignment(overlapStr1, overlapStr2);
  59. for (const [len, blocks] of Object.entries(alignmentContent)) {
  60. alignmentHub[len] = alignmentHub[len] ? [...new Set([...alignmentHub[len], ...blocks])] : blocks;
  61. }
  62. }
  63. return alignmentHub;
  64. }
  65. // 对齐
  66. function alignment(str1 = "", str2 = "") {
  67. const overlappingBlocks = {};
  68. let currentBlock = "";
  69.  
  70. for (let i = str1.length - 1; i >= 0; i--) {
  71. if (str1[i] === str2[i]) {
  72. currentBlock = str1[i] + currentBlock;
  73. } else if (currentBlock.length > 0) {
  74. const len = currentBlock.length;
  75. overlappingBlocks[len] = overlappingBlocks[len] || [];
  76. if (!overlappingBlocks[len].includes(currentBlock)) {
  77. overlappingBlocks[len].push(currentBlock);
  78. }
  79. currentBlock = "";
  80. }
  81. }
  82. if (currentBlock.length > 0) {
  83. const len = currentBlock.length;
  84. overlappingBlocks[len] = overlappingBlocks[len] || [];
  85. if (!overlappingBlocks[len].includes(currentBlock)) {
  86. overlappingBlocks[len].push(currentBlock);
  87. }
  88. }
  89.  
  90. return overlappingBlocks;
  91. }
  92. // 【同步排序算法】
  93. function sortAndSync(arr1, arr2, order = 'desc') {
  94. const compare = order === 'asc' ? (a, b) => a - b : (a, b) => b - a;
  95. arr1.map((v, i) => [v, arr2[i]])
  96. .sort((a, b) => compare(a[0], b[0]))
  97. .forEach(([v, o], i) => {
  98. arr1[i] = v;
  99. arr2[i] = o;
  100. });
  101. }
  102.  
  103.  
  104. // 【算法测试1】
  105. // console.log("-- 算法测试开始 --")
  106. // console.log(findOverlapBlocks("[推荐]sumatrapdf非常好用","pdf 推荐"))
  107. // console.log("-- 算法测试结束 --")
  108.  
  109. // 【算法测试2】
  110. // console.log("匹配度:", overlapMatchingDegree("好用的pdf工具", { "sumatrapdf": 10, "小而好用的pdf阅读器": 8, "https://www.sumatrapdfreader.org/downloadafter": 3 }));