打开/关闭菜单
打开/关闭外观设置菜单
打开/关闭个人菜单
未登录
未登录用户的IP地址会在进行任意编辑后公开展示。

用户:RedDragon/Test:修订间差异

来自Rizline中文维基
RedDragon
RedDragon留言 | 贡献 (优化算法:调整权重、增加大小写匹配、开头匹配、完全包含关系的额外加分;增加Fuse.js匹配算法;简化冗余代码)
第9行: 第9行:
                 style="padding: 0.5rem 1rem; background: #3366CC; color: #ffffff; font-size: 16px; border: none; border-radius: 0 5px 5px 0">搜索</button>
                 style="padding: 0.5rem 1rem; background: #3366CC; color: #ffffff; font-size: 16px; border: none; border-radius: 0 5px 5px 0">搜索</button>
         </div>
         </div>
         <div style="display: flex; justify-content: center; align-items: center; margin-top: 1rem;">
         <div style="display: flex; justify-content: center; align-items: center; margin-top: 1rem;">
             <label for="score-filter" style="margin-right: 0.5rem;">筛选匹配度 ≥</label>
             <label for="algorithm-select" style="margin-right: 0.5rem;">算法:</label>
            <input type="number" id="score-filter" value="2" min="1" max="100" style="width: 4rem; padding: 0.3rem;">
            <select id="algorithm-select" style="padding: 0.3rem; margin-right: 1rem;">
                <option value="custom">神秘算法</option>
                <option value="fuse">Fuse.js</option>
            </select>
            <div id="custom-filter-container">
                <label for="score-filter" style="margin-right: 0.5rem;">筛选匹配度 ≥</label>
                <input type="number" id="score-filter" value="3" min="1" max="100"
                    style="width: 4rem; padding: 0.3rem;">
            </div>
            <div id="fuse-filter-container" style="display: none;">
                <label for="fuse-threshold" style="margin-right: 0.5rem;">匹配阈值 ≤</label>
                <input type="number" id="fuse-threshold" value="0.4" min="0" max="1" step="0.1"
                    style="width: 4rem; padding: 0.3rem;">
            </div>
         </div>
         </div>
         <div style="margin-top: 100px">
         <div style="margin-top: 100px">
             <h3>搜索结果:</h3>
             <h3>搜索结果:</h3>
第24行: 第39行:
     </div>
     </div>


<script src="https://cdn.jsdelivr.net/npm/fuse.js@6.6.2/dist/fuse.min.js"></script>
<script>
<script>
    let fuseInstance = null
     document.addEventListener('DOMContentLoaded', function () {
     document.addEventListener('DOMContentLoaded', function () {
         initAllAliases()
         initAllAliases()
        initFuse()


         document.getElementById('alias-btn').addEventListener('click', searchSongs)
         document.getElementById('alias-btn').addEventListener('click', searchSongs)
         document.getElementById('alias-input').addEventListener('keypress', function (e) {
         document.getElementById('alias-input').addEventListener('keypress', function (e) {
             if (e.key == 'Enter') searchSongs()
             if (e.key == 'Enter') searchSongs()
        })
        document.getElementById('algorithm-select').addEventListener('change', function () {
            const algorithm = this.value
            const customContainer = document.getElementById('custom-filter-container')
            const fuseContainer = document.getElementById('fuse-filter-container')
            if (algorithm == 'fuse') {
                customContainer.style.display = 'none'
                fuseContainer.style.display = 'block'
            } else {
                customContainer.style.display = 'block'
                fuseContainer.style.display = 'none'
            }
            searchSongs()
         })
         })
     })
     })
第44行: 第79行:
             li.innerHTML = `<span class="song-title">${song.title || ''}</span>: <span class="aliases">${aliasText}</span>`
             li.innerHTML = `<span class="song-title">${song.title || ''}</span>: <span class="aliases">${aliasText}</span>`
             container.appendChild(li)
             container.appendChild(li)
        })
    }
    function initFuse() {
        const fuseOptions = {
            includeScore: true,
            includeMatches: true,
            threshold: 0.4,
            minMatchCharLength: 1,
            keys: ['title', 'aliases']
        }
        const searchData = songlist.map(function (song) {
            return {
                id: song.title,
                title: song.title,
                aliases: song.aliases ? song.aliases.join(' ') : ''
            }
        })
        fuseInstance = new Fuse(searchData, fuseOptions)
    }
    // Fuse.js搜索函数
    function searchWithFuse(searchText, threshold) {
        if (!fuseInstance) initFuse()
        const results = fuseInstance.search(searchText, {
            limit: 50,
            threshold: threshold
        })
        return results.map(function (result) {
            const song = songlist.find(function (s) {
                return s.title == result.item.id
            })
            return {
                song: song,
                score: Math.round((1 - (result.score || 0)) * 100),
                matched: result.matches ? result.matches[0].value : '',
                matchedAlias: '',
                fuseScore: result.score
            }
         })
         })
     }
     }
第51行: 第131行:
     允许间隔,顺序匹配
     允许间隔,顺序匹配
     每匹配一个字符加1分
     每匹配一个字符加1分
     连续匹配额外加分*/
     连续匹配加0.5分
    大小写精确匹配加0.3分
    开头匹配加1.5分
    完全包含关系额外加分
    */
     function getMatchScore(input, target) {
     function getMatchScore(input, target) {
         if (!input || !target) return { score: 0, matched: "" }
         if (!input || !target) return { score: 0, matched: "" }
        const originalInput = input
        const originalTarget = target
         input = input.toLowerCase()
         input = input.toLowerCase()
         target = target.toLowerCase()
         target = target.toLowerCase()
        if (input == target) return { score: 100, matched: input }


         // 输入作为目标的子序列
         if (input == target) return { score: 100, matched: originalTarget }
         let score1 = 0, matched1 = "", lastPos1 = -1, bonus1 = 0, pos1 = 0
 
         for (let i = 0; i < input.length; i++) {
         let containBonus = 0
             let found = false
         if (input.includes(target)) {
            for (let j = pos1; j < target.length; j++) {
             if (target.length >= 5) {
                 if (input[i] == target[j]) {
                if (input.length >= 3) {
                     score1 += 1
                    containBonus = 6 + (target.length * 0.3)
                    matched1 += input[i]
                }
                    if (lastPos1 >= 0) {
            } else {
                        if (j == lastPos1 + 1) {
                 if (input.length >= 2) {
                            bonus1 += 1
                     containBonus = 6 + (target.length * 0.3)
                        }
                }
                    }
            }
                    lastPos1 = j
        } else if (target.includes(input)) {
                     pos1 = j + 1
            if (target.length >= 5) {
                    found = true
                if (input.length >= 3) {
                    break
                    containBonus = 5 + (input.length * 0.3)
                }
            } else {
                if (input.length >= 2) {
                     containBonus = 5 + (input.length * 0.3)
                 }
                 }
             }
             }
            if (!found) break
         }
         }
        score1 += bonus1


         // 目标作为输入的子序列
         function calculateScore(src, tgt, originalSrc, originalTgt) {
        let score2 = 0, matched2 = "", lastPos2 = -1, bonus2 = 0, pos2 = 0
            let score = 0, matched = "", lastPos = -1, bonus = 0, pos = 0, caseBonus = 0
        for (let i = 0; i < target.length; i++) {
            for (let i = 0; i < src.length; i++) {
            let found = false
                let found = false
            for (let j = pos2; j < input.length; j++) {
                for (let j = pos; j < tgt.length; j++) {
                if (target[i] == input[j]) {
                    if (src[i] == tgt[j]) {
                    score2 += 1
                        score++
                    matched2 += target[i]
                        matched += originalTgt[j]
                    if (lastPos2 >= 0) {
 
                         if (j == lastPos2 + 1) {
                         if (originalSrc[i] == originalTgt[j]) {
                             bonus2 += 1
                             caseBonus += 0.3
                         }
                         }
                        if (lastPos >= 0) {
                            if (j == lastPos + 1) {
                                bonus += 0.5
                            }
                        }
                        lastPos = j
                        pos = j + 1
                        found = true
                        break
                     }
                     }
                    lastPos2 = j
                    pos2 = j + 1
                    found = true
                    break
                 }
                 }
                if (!found) break
            }
            let startBonus = 0
            if (matched.length > 0) {
                if (tgt.indexOf(src[0]) == 0) {
                    startBonus = 1.5
                }
            }
            return {
                score: score + bonus + caseBonus + startBonus + containBonus,
                matched
             }
             }
            if (!found) break
         }
         }
        score2 += bonus2


         if (score1 >= score2) {
        const result1 = calculateScore(input, target, originalInput, originalTarget)
             return { score: score1, matched: matched1 }
        const result2 = calculateScore(target, input, originalTarget, originalInput)
 
         if (result1.score >= result2.score) {
             return result1
         } else {
         } else {
             return { score: score2, matched: matched2 }
             return result2
         }
         }
     }
     }


     function searchSongs() {
     function searchSongs() {
         const searchText = document.getElementById('alias-input').value.trim().toLowerCase()
         const searchText = document.getElementById('alias-input').value.trim()
         const resultsContainer = document.getElementById('alias-results')
         const resultsContainer = document.getElementById('alias-results')
         const resc = Number(document.getElementById('score-filter').value) || 2
         const algorithm = document.getElementById('algorithm-select').value


         if (!searchText) {
         if (!searchText) {
第121行: 第229行:
         }
         }


         const results = songlist.map(function (song) {
         let results = []
            let best = getMatchScore(searchText, song.title ? song.title.toLowerCase() : '')
 
            let bestAlias = ""
        if (algorithm == 'fuse') {
            if (song.aliases) {
            const threshold = parseFloat(document.getElementById('fuse-threshold').value) || 0.4
                if (song.aliases.length > 0) {
            results = searchWithFuse(searchText, threshold)
                    song.aliases.forEach(function (alias) {
            // console.log(`Fuse.js搜索: "${searchText}", 阈值: ${threshold}, 结果数: ${results.length}`)
                        let result = getMatchScore(searchText, alias.toLowerCase())
 
                        if (result.score > best.score) {
        } else {
                            best = result
            const resc = Number(document.getElementById('score-filter').value) || 3
                            bestAlias = alias
            results = songlist.map(function (song) {
                         }
                let best = getMatchScore(searchText, song.title || '')
                     })
                let bestAlias = ""
                if (song.aliases) {
                    if (song.aliases.length > 0) {
                        song.aliases.forEach(function (alias) {
                            let result = getMatchScore(searchText, alias)
                            if (result.score > best.score) {
                                best = result
                                bestAlias = alias
                            }
                         })
                     }
                }
                return {
                    song: song,
                    score: best.score,
                    matched: best.matched,
                    matchedAlias: bestAlias
                 }
                 }
             }
             }).filter(function (result) {
            return {
                // if (result.score >= resc) {
                song: song,
                //    console.log(
                score: best.score,
                //        `${result.song.title}: [${result.matched}]${(result.matchedAlias ? ` (${result.matchedAlias})` : "")}  ${result.score} `
                matched: best.matched,
                //    )
                matchedAlias: bestAlias
                // }
            }
                return result.score >= resc
        }).filter(function (result) {
            }).sort(function (a, b) {
            // if (result.score >= resc) {
                return b.score - a.score
            //    console.log(
            })
            //        `${result.song.title}: [${result.matched}]${(result.matchedAlias ? ` (${result.matchedAlias})` : "")}  ${result.score} `
         }
            //    )
            // }
            return result.score >= resc
        }).sort(function (a, b) {
            return b.score - a.score
         })


         if (results.length == 0) {
         if (results.length == 0) {

2025年9月15日 (一) 01:10的版本

搜索结果:

别名列表: