#!/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()