- 实现智能排序:数字 -> 字母 -> 其他符号 - 添加 smartSort() 方法支持自然数值排序 - 默认启用排序功能,用户无需设置 - 支持多语言字符(中文、日文、英文等) - 添加完整的测试工具和文档 新增文件: - test_sort.html (可视化测试页面) - verify_sort.py (Python验证脚本) - verify_sort.js (Node.js验证脚本) - SORT_FEATURE.md (功能说明) - SORT_USAGE.md (使用指南) - QUICKSTART_SORT.md (快速开始) - IMPLEMENTATION_SUMMARY.md (实现总结) - CHANGELOG_SORT.md (更新日志) - UPDATE_SUMMARY.md (更新说明) 修改文件: - public/src/js/songselect.js (添加智能排序逻辑) - README.md (更新功能介绍)
210 lines
5.6 KiB
Python
210 lines
5.6 KiB
Python
#!/usr/bin/env python3
|
||
# -*- coding: utf-8 -*-
|
||
"""
|
||
歌曲排序功能验证脚本
|
||
运行方式: python verify_sort.py
|
||
"""
|
||
|
||
import locale
|
||
from functools import cmp_to_key
|
||
|
||
# 设置本地化以支持多语言排序
|
||
locale.setlocale(locale.LC_ALL, '')
|
||
|
||
def smart_sort(title_a, title_b):
|
||
"""
|
||
智能排序函数(与 JavaScript 版本逻辑相同)
|
||
"""
|
||
def get_char_type(char):
|
||
"""判断字符类型"""
|
||
if not char:
|
||
return 3 # 空字符串排在最后
|
||
|
||
code = ord(char)
|
||
|
||
# 数字 (0-9)
|
||
if 48 <= code <= 57:
|
||
return 0
|
||
|
||
# 英文字母 (A-Z, a-z)
|
||
if (65 <= code <= 90) or (97 <= code <= 122):
|
||
return 1
|
||
|
||
# 其他所有字符(符号、中文、日文等)
|
||
return 2
|
||
|
||
# 获取首字符类型
|
||
type_a = get_char_type(title_a[0] if title_a else None)
|
||
type_b = get_char_type(title_b[0] if title_b else None)
|
||
|
||
# 首先按字符类型排序:数字 < 字母 < 其他符号
|
||
if type_a != type_b:
|
||
return type_a - type_b
|
||
|
||
# 同类型字符,使用自然排序
|
||
# Python 的 locale.strcoll 提供类似 localeCompare 的功能
|
||
try:
|
||
# 尝试数值比较(对于纯数字开头的字符串)
|
||
if type_a == 0: # 数字类型
|
||
# 提取开头的数字部分进行比较
|
||
num_a = ''
|
||
num_b = ''
|
||
|
||
for c in title_a:
|
||
if c.isdigit():
|
||
num_a += c
|
||
else:
|
||
break
|
||
|
||
for c in title_b:
|
||
if c.isdigit():
|
||
num_b += c
|
||
else:
|
||
break
|
||
|
||
if num_a and num_b:
|
||
num_cmp = int(num_a) - int(num_b)
|
||
if num_cmp != 0:
|
||
return num_cmp
|
||
|
||
# 字符串比较(忽略大小写)
|
||
return locale.strcoll(title_a.lower(), title_b.lower())
|
||
except:
|
||
# 如果 locale 比较失败,使用简单的字符串比较
|
||
if title_a.lower() < title_b.lower():
|
||
return -1
|
||
elif title_a.lower() > title_b.lower():
|
||
return 1
|
||
return 0
|
||
|
||
def get_type_label(title):
|
||
"""获取字符类型标签"""
|
||
if not title:
|
||
return '[空]'
|
||
|
||
code = ord(title[0])
|
||
|
||
if 48 <= code <= 57:
|
||
return '[数字]'
|
||
if (65 <= code <= 90) or (97 <= code <= 122):
|
||
return '[字母]'
|
||
return '[其他]'
|
||
|
||
def main():
|
||
# 测试数据
|
||
test_songs = [
|
||
"太鼓の達人",
|
||
"Zyxwv Test",
|
||
"123 Song",
|
||
"abc melody",
|
||
"456 rhythm",
|
||
"*Special*",
|
||
"10 drums",
|
||
"あいうえお",
|
||
"2 beats",
|
||
"ZZZ Final",
|
||
"1st Place",
|
||
"100 percent",
|
||
"ドンだー!",
|
||
"Battle No.1",
|
||
"~奇跡~",
|
||
"777",
|
||
"Angel Beats",
|
||
"カノン",
|
||
"Don't Stop",
|
||
"零 -ZERO-",
|
||
"3pieces",
|
||
"Apple",
|
||
"燎原ノ舞",
|
||
"99 Balloons",
|
||
"Brave Heart",
|
||
"夏祭り",
|
||
"5 Elements",
|
||
"50音",
|
||
"Zephyr",
|
||
"α wave"
|
||
]
|
||
|
||
print('\n' + '=' * 60)
|
||
print('🥁 Taiko Web - 歌曲智能排序功能测试')
|
||
print('=' * 60 + '\n')
|
||
|
||
print(f'📋 原始歌曲列表 (共 {len(test_songs)} 首):')
|
||
print('-' * 60)
|
||
for i, song in enumerate(test_songs, 1):
|
||
print(f'{i:2d}. {song}')
|
||
|
||
print('\n' + '=' * 60)
|
||
print('⚙️ 执行智能排序...\n')
|
||
|
||
# 排序
|
||
sorted_songs = sorted(test_songs, key=cmp_to_key(smart_sort))
|
||
|
||
print('✅ 排序后的歌曲列表:')
|
||
print('-' * 60)
|
||
|
||
current_type = None
|
||
for i, song in enumerate(sorted_songs, 1):
|
||
type_label = get_type_label(song)
|
||
|
||
# 检测类型变化,添加分隔符
|
||
if current_type != type_label:
|
||
if current_type is not None:
|
||
print() # 空行分隔不同类型
|
||
current_type = type_label
|
||
|
||
print(f'{i:2d}. {song:25s} {type_label}')
|
||
|
||
print('\n' + '=' * 60)
|
||
print('📊 统计信息:')
|
||
print('-' * 60)
|
||
|
||
# 统计各类型数量
|
||
number_count = sum(1 for song in sorted_songs if get_type_label(song) == '[数字]')
|
||
letter_count = sum(1 for song in sorted_songs if get_type_label(song) == '[字母]')
|
||
other_count = sum(1 for song in sorted_songs if get_type_label(song) == '[其他]')
|
||
|
||
print(f'数字开头: {number_count} 首')
|
||
print(f'字母开头: {letter_count} 首')
|
||
print(f'其他开头: {other_count} 首')
|
||
print(f'总计: {len(sorted_songs)} 首')
|
||
|
||
print('\n' + '=' * 60)
|
||
print('✨ 排序规则验证:')
|
||
print('-' * 60)
|
||
|
||
# 验证排序是否正确
|
||
is_valid = True
|
||
prev_type = -1
|
||
|
||
for song in sorted_songs:
|
||
code = ord(song[0])
|
||
|
||
if 48 <= code <= 57:
|
||
current_type = 0
|
||
elif (65 <= code <= 90) or (97 <= code <= 122):
|
||
current_type = 1
|
||
else:
|
||
current_type = 2
|
||
|
||
if current_type < prev_type:
|
||
is_valid = False
|
||
print(f'❌ 错误: "{song}" (类型 {current_type}) 出现在类型 {prev_type} 之后')
|
||
|
||
prev_type = current_type
|
||
|
||
if is_valid:
|
||
print('✅ 排序规则验证通过!')
|
||
print(' - 数字优先')
|
||
print(' - 字母次之')
|
||
print(' - 其他符号最后')
|
||
else:
|
||
print('❌ 排序规则验证失败!')
|
||
|
||
print('\n' + '=' * 60)
|
||
print('🎵 测试完成!')
|
||
print('=' * 60 + '\n')
|
||
|
||
if __name__ == '__main__':
|
||
main()
|