打开/关闭搜索
搜索
打开/关闭菜单
139
836
236
7018
Rizline中文维基
导航
首页
最近更改
随机页面
♪ 随机曲目
@ 邮件联系
MediaWiki帮助
特殊页面
上传文件
Rizline中文维基
方针
格式手册
著作权
帮助
维基入门
基础语法
图像
表格
介绍
机制
设置
活动
收藏
挑战
版本更新概要
列表
曲目列表
插画作者列表
曲目作者列表
Rizcard列表
版式列表
称号列表
成就列表
外部链接
Rizline官方bilibili账号
Rizline中文维基bilibili账号
排错
特殊页面
封禁用户
站点统计
状态检测
打开/关闭外观设置菜单
通知
打开/关闭个人菜单
未登录
未登录用户的IP地址会在进行任意编辑后公开展示。
user-interface-preferences
中文(简体)
个人工具
创建账号
登录
查看“︁用户:RedDragon/Test”︁的源代码
来自Rizline中文维基
查看
阅读
查看源代码
查看历史
associated-pages
用户页
讨论
更多操作
←
用户:RedDragon/Test
因为以下原因,您没有权限编辑该页面:
您请求的操作仅限属于这些用户组的用户执行:
管理员
、emailconfirmed
您必须确认您的电子邮件地址才能编辑页面。请通过
参数设置
设置并确认您的电子邮件地址。
您可以查看和复制此页面的源代码。
<html> <div style="margin: 5%"> <div style="margin-top: 100px; display: flex; justify-content: center; align-items: center"> <input type="text" id="alias-input" style="padding: 0.6rem; background: #ffffff; font-size: 16px; width: 14rem; border-radius: 5px 0 0 5px" placeholder="输入曲目名称或别名..."> <button id="alias-btn" style="padding: 0.5rem 1rem; background: #3366CC; color: #ffffff; font-size: 16px; border: none; border-radius: 0 5px 5px 0">搜索</button> </div> <div style="display: flex; justify-content: center; align-items: center; margin-top: 1rem;"> <label for="algorithm-select" style="margin-right: 0.5rem;">算法:</label> <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="4" 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 style="margin-top: 100px"> <h3>搜索结果:</h3> <div id="alias-results" style="color: #333"> </div> </div> <div style="margin-top: 100px"> <h3>别名列表:</h3> <ul id="all-alias" style="color: #333"></ul> </div> </div> <script src="https://cdn.jsdelivr.net/npm/fuse.js@6.6.2/dist/fuse.min.js"></script> <script> let fuseInstance = null document.addEventListener('DOMContentLoaded', function () { initAllAliases() initFuse() document.getElementById('alias-btn').addEventListener('click', searchSongs) document.getElementById('alias-input').addEventListener('keypress', function (e) { 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() }) }) function initAllAliases() { const container = document.getElementById('all-alias') container.innerHTML = '' songlist.forEach(function (song) { const li = document.createElement('li') const aliases = song.aliases || [] let aliasText = aliases.length > 0 ? aliases.join('、') : '<span style="color:#888">无别名</span>' li.innerHTML = `<span class="song-title">${song.title || ''}</span>: <span class="aliases">${aliasText}</span>` 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 } }) } /*计算权重 输入字符只在目标字符串中匹配一次 允许间隔,顺序匹配 每匹配一个字符加1分 连续匹配加0.5分 大小写精确匹配加0.3分 开头匹配加1.5分 完全包含关系额外加分 */ function getMatchScore(input, target) { if (!input || !target) return { score: 0, matched: "" } const originalInput = input const originalTarget = target input = input.toLowerCase() target = target.toLowerCase() if (input == target) return { score: 100, matched: originalTarget } let containBonus = 0 if (input.includes(target)) { if (target.length >= 5) { if (input.length >= 3) { containBonus = 6 + (target.length * 0.3) } } else { if (input.length >= 2) { containBonus = 6 + (target.length * 0.3) } } } else if (target.includes(input)) { if (target.length >= 5) { if (input.length >= 3) { containBonus = 5 + (input.length * 0.3) } } else { if (input.length >= 2) { containBonus = 5 + (input.length * 0.3) } } } function calculateScore(src, tgt, originalSrc, originalTgt) { let score = 0, matched = "", lastPos = -1, bonus = 0, pos = 0, caseBonus = 0 let skipCount = 0 const maxSkip = 2 for (let i = 0; i < src.length; i++) { let found = false const srcChar = src[i] const associatedChars = getAssociatedChars(srcChar) for (let j = pos; j < tgt.length; j++) { const tgtChar = tgt[j] if (srcChar === tgtChar || associatedChars.includes(tgtChar)) { score++ matched += originalTgt[j] if (originalSrc[i] == originalTgt[j]) { caseBonus += 0.3 } else if (associatedChars.includes(tgtChar)) { caseBonus += 0.1 } if (lastPos >= 0) { if (j == lastPos + 1) { bonus += 0.5 } } lastPos = j pos = j + 1 found = true break } } if (!found) { skipCount++ if (skipCount > maxSkip) { 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 } } const result1 = calculateScore(input, target, originalInput, originalTarget) const result2 = calculateScore(target, input, originalTarget, originalInput) if (result1.score >= result2.score) { return result1 } else { return result2 } } function searchSongs() { const searchText = document.getElementById('alias-input').value.trim() const resultsContainer = document.getElementById('alias-results') const algorithm = document.getElementById('algorithm-select').value if (!searchText) { resultsContainer.innerHTML = '<div>输入关键词进行搜索</div>' return } let results = [] if (algorithm == 'fuse') { const threshold = parseFloat(document.getElementById('fuse-threshold').value) || 0.4 results = searchWithFuse(searchText, threshold) // console.log(`Fuse.js搜索: "${searchText}", 阈值: ${threshold}, 结果数: ${results.length}`) } else { const resc = Number(document.getElementById('score-filter').value) || 4 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) { // if (result.score >= resc) { // 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) { resultsContainer.innerHTML = '<div>没有找到匹配的曲目</div>' } else { resultsContainer.innerHTML = '' results.forEach(function (result) { const div = document.createElement('div') div.className = 'result-item' div.style.margin = "0 0 0.5rem 1rem" div.style.lineHeight = "1.5" var songTitle = result.song.title || '' var link = `<a href="/${encodeURIComponent(songTitle)}/wiki" title="${songTitle}">${songTitle}</a>` div.innerHTML = `<div class="song-title">${link}</div> <div class="aliases" style="font-size: 13px; margin-left: 1rem">alias: ${result.song.aliases.join('、')}</div>` resultsContainer.appendChild(div) }) } } function getAssociatedChars(char) { const associations = new Set([char]) if (charAssociations[char]) { charAssociations[char].forEach(assocChar => associations.add(assocChar)) } for (const [key, values] of Object.entries(charAssociations)) { if (values.includes(char)) { associations.add(key) } } return Array.from(associations) } // 关联字符库,冒号前的字符可通过中括号里的字符匹配 const charAssociations = { 'ィ': ['イ', '亻', 'ィ'], 'イ': ['ィ', '亻', 'イ'], 'ェ': ['エ', '工', 'ェ'], 'エ': ['ェ', '工', 'エ'], '的': ['得', '地', 'の', '之'], '得': ['的', '地', 'の', '之'], 'の': ['的', '得', '地', '之'], '之': ['的', '得', 'の', '地'], '地': ['的', '得', 'の', '之'], '*': ['x', '×'], 'x': ['*', '×'], '×': ['x', '*'], '℟': ['R'], 'Α': ['α', 'A', 'a', 'alpha'], 'α': ['Α', 'a', 'A', 'alpha'], 'alpha': ['Α', 'α', 'A', 'a'], } // 别名库 const songlist = [ { title: "Pastel Lines", aliases: ["粉彩线条"] }, { title: "Gleam feat. ふわまろ", aliases: [] }, { title: "Power Attack", aliases: ["力攻"] }, { title: "Skyscape", aliases: [] }, { title: "On And On!!", aliases: ["oao", "onandon", "上和上", "我们相亲相爱的"] }, { title: "Polygons", aliases: [] }, { title: "Abgrund", aliases: [] }, { title: "Journey To The Rainbows", aliases: ["彩虹之旅", "彩虹是个好东西"] }, { title: "Midnight Flux", aliases: [] }, { title: "NO ONE YES MAN", aliases: ["noym", "没一个是人"] }, { title: "Clock Paradox", aliases: ["时钟悖论","时悖","钟漠","时钟佯谬","钟盒"] }, { title: "F℟IEND", aliases: ["恶魔朋友"] }, { title: "Shattered", aliases: [] }, { title: "Swing Sweet Twee Dance feat. ななきなな", aliases: ["sstd"] }, { title: "V!rtuaresort", aliases: ["Virtuaresort"] }, { title: "Dice 20", aliases: [] }, { title: "macro.wav", aliases: ["宏波", "宏波炉","滴滴滴滴","微波炉2"] }, { title: "The Next Arcady", aliases: [] }, { title: "Sakura Fubuki", aliases: ["樱吹雪"] }, { title: "Tempest", aliases: ["风暴"] }, { title: "Authentic (Game ver.)", aliases: [] }, { title: "MilK", aliases: ["牛奶"] }, { title: "ILLEGAL LEGACY", aliases: ["il", "非法遗产"] }, { title: "竹", aliases: ["小心立秋"] }, { title: "R.I.P.", aliases: ["rip"] }, { title: "Empire", aliases: ["王朝"] }, { title: "DropDown", aliases: ["坠落","dd"] }, { title: "Contact", aliases: ["连接"] }, { title: "CANDYLAND", aliases: ["糖果岛","初代魔王"] }, { title: "Arcade ViruZ", aliases: ["街机病毒"] }, { title: "LINK x LIN#S", aliases: ["连接起来吧"] }, { title: "LEONIDS", aliases: ["狮子座", "星座"] }, { title: "FORTALiCE", aliases: [] }, { title: "Paradial Resonator", aliases: ["pr"] }, { title: "Lavender Leaf (feat. Lexi)", aliases: ["薰衣草"] }, { title: "Puppet Show", aliases: ["Jazz"] }, { title: "Vicious Mockery", aliases: ["vm","狂暴之嘲","vici","vc","维C","狂暴猴子"] }, { title: "BRAVE: ROAD", aliases: ["br", "勇气之路", "勇敢之路", "勇路"] }, { title: "Dot-Line (feat. ななひら)", aliases: ["点线"] }, { title: "光 (阿卡姆巫师 Remix)", aliases: ["阿卡姆光"] }, { title: "Lost Future", aliases: ["失落未来"] }, { title: "sAtElLites", aliases: ["卫星"] }, { title: "Intruder", aliases: [] }, { title: "Rule The World", aliases: ["定义世界"] }, { title: "felys -final remix-", aliases: ["菲莉丝","飞雷神"] }, { title: "Destr0yer", aliases: ["d0","毁灭者","削除射线","sakuzyo beam"] }, { title: "crystallized", aliases: ["结晶"] }, { title: "Cosmos Capsule", aliases: ["交互胶囊"] }, { title: "Yellow Shining!! feat. 成田なる", aliases: [] }, { title: "Abatement", aliases: [] }, { title: "Rapture", aliases: [] }, { title: "Turning POINT", aliases: [] }, { title: "Reversed Zenith", aliases: [] }, { title: "Restricted Access", aliases: ["ra","限制通道","立入禁止"] }, { title: "The Last Page", aliases: ["最后一页","终页"] }, { title: "Super Universe (Knighthood Remix)", aliases: ["超宇宙","超宇", "Super Universe Remix"] }, { title: "Enneaquest", aliases: [] }, { title: "Colorful Flavor", aliases: [] }, { title: "Abiogenesis", aliases: ["无生源论"] }, { title: "Revenant", aliases: ["荒野猎人"] }, { title: "Antler", aliases: ["鹿角"] }, { title: "Contortion", aliases: [] }, { title: "Bring Me Back", aliases: ["带我回来"] }, { title: "Hullbreaker", aliases: [] }, { title: "D-Birth", aliases: [] }, { title: "NightTheater", aliases: ["夜剧场", "夜剧院", "NT"] }, { title: "Grimheart", aliases: ["冷酷的心", "寒冷的心", "冷心"] }, { title: "Encrux", aliases: ["翼龙"] }, { title: "slic.hertz", aliases: [] }, { title: "Giselle", aliases: ["吉赛尔"] }, { title: "Afterdark", aliases: ["黑暗之后"] }, { title: "蒼天 (Sta's Key-Kai mix)", aliases: ["苍天"] }, { title: "Conway's Child", aliases: ["康威之子"] }, { title: "Crimsonate", aliases: [] }, { title: "Sthenno", aliases: ["丝西娜"] }, { title: "Kaguya", aliases: ["辉夜姬"] }, { title: "Relieve", aliases: [] }, { title: "Alexandrite", aliases: ["变石"] }, { title: "Hydra", aliases: ["九头蛇"] }, { title: "漂流", aliases: [] }, { title: "Comet Coaster", aliases: [] }, { title: "DOMINATOR", aliases: [] }, { title: "天灵灵地灵灵", aliases: [] }, { title: "Psychometry", aliases: ["心灵感应"] }, { title: "Electric Comet", aliases: ["电子彗星"] }, { title: "Eschatology", aliases: ["末世论"] }, { title: "너를 그리는 밤하늘의 이야기 (Planetarium) prod. Scarlette", aliases: ["天文馆","一串韩文","韩文字括号英文字括号英文字"] }, { title: "Avataar ~Reincarnation of Kalpa~", aliases: ["Avataar","arok","卡尔帕转世","化生~劫之轮回~","劫之轮回","蓝魔王"] }, { title: "Frozen Heart", aliases: ["冰心"] }, { title: "amethyst", aliases: ["紫水晶"] }, { title: "Alfheim's faith", aliases: [] }, { title: "翠杜", aliases: ["脆肚","suito"] }, { title: "驟雨の狭間", aliases: ["骤雨狭间", "骤雨的缝隙","骤雨的隙间","骤雨","周瑜"] }, { title: "enchanted love", aliases: ["附魔爱","醉心之爱","醉心爱"] }, { title: "Crazy Audiophile", aliases: [] }, { title: "419kB", aliases: [] }, { title: "VICIOUS", aliases: ["狂暴"] }, { title: "Crush Alcohol", aliases: ["酒精"] }, { title: "インフェルノシティ", aliases: ["地狱城", "地狱都市","亻ンフ工儿丿シ亍亻"] }, { title: "No-name Requiem", aliases: ["无名安魂曲"] }, { title: "Change the Game feat. 松永依織", aliases: [] }, { title: "T+ VS SHARK", aliases: ["OMG!!! It's a SHARK!!!"] }, { title: "Future Downloader", aliases: ["未来下载器"] }, { title: "Echo over you...", aliases: [] }, { title: "Fairy's Crown", aliases: [] }, { title: "Graves -Ancient Memories-", aliases: [] }, { title: "Clouds clear and...", aliases: [] }, { title: "NLAMTA", aliases: [] }, { title: "Antikythera", aliases: [] } ] </script> </html>
返回
用户:RedDragon/Test
。
查看“︁用户:RedDragon/Test”︁的源代码
来自Rizline中文维基