-
Notifications
You must be signed in to change notification settings - Fork 1
Helpers
lyrics-core 提供了一组无状态的辅助工具模块,位于 lyrics_helper::helpers 命名空间下。
pub fn get_lyrics_types(input: &str) -> LyricsRawTypes识别输入文本的歌词格式。
检测判定顺序:
-
结构化信封判定:先尝试用
serde_json解析,依次匹配 Apple Music、Spotify、Musixmatch 与网易云完整 YRC 的 JSON 特征结构;再用quick-xml扫描 XML 节点,区分 TTML 与 QRC XML 信封。通过真实解析结构判定,避免正文包含关键词时发生误判。 -
行特征与正则判定:当非结构化数据时,按行扫描正则:
[type:LyricifyLines]-> KRC -> YRC -> Lyricify Syllable -> QRC -> Lyricify Lines -> LRC。 - 均不匹配时返回
LyricsRawTypes::Unknown。
use lyrics_helper::helpers::type_helper::get_lyrics_types;
use lyrics_helper::LyricsRawTypes;
let content = "[00:12.00]Hello World\n[00:15.50]Second line";
assert_eq!(get_lyrics_types(content), LyricsRawTypes::Lrc);Note
QrcFull、YrcFull、AppleJson 判定成功时表示输入为外层传输信封。parse() 对信封类型返回 None,调用方需先提取内嵌歌词文本。
每种格式均提供独立的 is_* 谓词函数(签名均为 fn(&str) -> bool):
-
is_lrc、is_lyricify_syllable、is_lyricify_lines -
is_qrc、is_qrc_full(QRC XML 信封) -
is_krc(已解密文本) -
is_yrc、is_yrc_full(网易云 JSON 信封) -
is_ttml、is_apple_json、is_spotify、is_musixmatch
类型转换与显示名:
-
try_parse_raw_type(name: &str) -> Option<LyricsRawTypes>:按格式名称解析(如"qrc (xml)"->QrcFull)。 -
get_raw_type_display_name(raw_type: LyricsRawTypes) -> String:获取可读格式名称。 -
is_lyrics_type(lyrics: &str, t: LyricsTypes) -> bool:输入是否匹配指定歌词类型。 -
is_lyrics_type_any(lyrics: &str, types: &[LyricsTypes]) -> bool:输入是否属于给定类型列表之一。
pub fn add_offset(lines: &mut [LineInfo], offset: i32)对歌词行批量应用时间偏移(毫秒)。内部实现为 time -= offset:
-
正值:时间戳前移,歌词更早出现(与标准 LRC
[offset:]语义一致)。 - 负值:时间戳后移,歌词延后出现。
- 递归平移所有
sub_line(背景和声)。 - 音节行的行时间(
start_time/end_time)与各音节自身的起止时间一同平移。
use lyrics_helper::helpers::offset_helper::add_offset;
use lyrics_helper::{parse, LyricsRawTypes};
let mut data = parse("[00:12.00]Hello World", LyricsRawTypes::Lrc).unwrap();
if let Some(lines) = &mut data.lines {
// 前移 500ms:12.000s 变为 11.500s
add_offset(lines, 500);
}-
add_offset_to_syllables(syllables: &mut [SyllableInfo], offset: i32):平移普通音节切片。 -
add_offset_to_syllable_items(syllables: &mut [SyllableItem], offset: i32):平移抽象音节项,内部合并的FullSyllableInfo各子音节同步调整。
基于 ferrous-opencc 实现的快速繁简文本转换。转换器内部懒加载并全局复用。
use lyrics_helper::helpers::chinese_helper::{to_simplified, to_traditional};
assert_eq!(to_simplified("漢語歌詞"), "汉语歌词");
assert_eq!(to_traditional("汉语歌词"), "漢語歌詞");pub fn to_simplified_forced(text: &str) -> String增强型简繁转换:在 OpenCC 转换基础上,针对词典未覆盖的「藉/咀/昇/髒」等异体字做强制替换,对应上游 ChineseHelper.ToSC(text, force: true),用于曲目匹配打分。
-
format_time_ms_to_timestamp_string(time_ms: f32) -> String:将毫秒转为mm:ss.SSS格式字符串。负值作为0处理。 -
remove_front_back_brackets(s: &str) -> String:剥离首尾成对的圆括号(半角()或全角())。 -
is_number(s: &str) -> bool:判断字符串是否非空且纯由 ASCII 数字组成。
use lyrics_helper::helpers::string_helper::{has_chinese, is_chinese_or_japanese_character};
// has_chinese 严格限定在 CJK 统一表意文字区 (\u{4E00}-\u{9FFF})
assert!(has_chinese("中文"));
assert!(!has_chinese("ひらがな"));
// is_chinese_or_japanese_character 覆盖平假名、片假名、扩展 A 等,用于音节词边界判定
assert!(is_chinese_or_japanese_character('ひ'));-
collapse_whitespace(s: &str) -> String:将连续空白(空格、Tab、换行等)折叠为单个半角空格,并去除首尾空白。 -
remove_duo_spaces(s: &str) -> String:仅将连续的两个以上半角空格压缩为单个空格,不执行首尾 trim。 -
compute_text_same(s1: &str, s2: &str, case_sensitive: bool) -> f64:基于最长公共子序列(LCS)计算相似度分值(0.0 ~ 100.0)。 -
lcs_length(s1: &str, s2: &str) -> usize:计算两字符串的最长公共子序列长度。
处理带 None 的时间戳极值计算:
-
min_opt(a: Option<i32>, b: Option<i32>) -> Option<i32>:返回两者中的较小值;均为None时返回None。 -
max_opt(a: Option<i32>, b: Option<i32>) -> Option<i32>:返回两者中的较大值;均为None时返回None。
部分平台歌词(如 LRC/QRC/YRC)未定义结构化声部或伴唱字段,转录者常将歌手标签写在行首(如 周杰伦:)或用括号包裹伴唱(如 (yeah))。本模块提供从文本约定中还原结构化信息的能力:
| 函数 | 功能说明 |
|---|---|
apply_speaker_labels(lines, artists) |
根据曲目歌手列表识别行首歌手名或独立标签行,将对齐属性分别置为 Left(主唱)与 Right(合唱/副部);独立标签行将被清除 |
split_background_vocals(lines) |
将逐字行内的括号内容拆分为该行的背景和声子行(sub_line) |
unwrap_brackets(text) |
去除短语外层的包围括号 |
fold_bracketed_echoes(lines) |
将整行均为括号的伴唱行并入前一行的 sub_line
|
merge_continued_lines(lines) |
根据行尾逗号或标点,将跨行书写的断句合并回主行 |
Important
上述函数会对歌词行结构进行破坏性修改(重排音节、合并/删除行),解析器不会自动调用。建议的组合调用顺序:
apply_speaker_labels -> split_background_vocals -> 关联翻译 -> fold_bracketed_echoes -> merge_continued_lines。
use lyrics_helper::helpers::conventions::{apply_speaker_labels, split_background_vocals};
use lyrics_helper::{LineInfo, LyricsAlignment, SyllableInfo};
let mut lines = vec![
LineInfo::new_line("周杰伦:".to_string(), Some(0), None),
LineInfo::new_syllable_with_time(
vec![
SyllableInfo::new("Hold ".to_string(), 1000, 1500).into(),
SyllableInfo::new("on (yeah)".to_string(), 1500, 2500).into(),
],
Some(1000),
None,
),
];
apply_speaker_labels(&mut lines, &["周杰伦".to_string()]);
split_background_vocals(&mut lines);
assert_eq!(lines.len(), 1); // 标签行已被移除
assert_eq!(lines[0].text_from_any(), "Hold on");
assert_eq!(lines[0].alignment(), LyricsAlignment::Left);
assert_eq!(lines[0].sub_line().unwrap().text_from_any(), "yeah");pub fn apply_word_timings(lines: &mut [LineInfo], word_lines: &[LineInfo])网易云 YRC 等逐词歌词通常存在转录缺失标点、分词吞空格等问题。apply_word_timings 将逐词文档(word_lines)的音节时间精确迁移至排版规范的逐行文本(lines)上:
- 行对齐:两份文档按行开始时间匹配(误差允许 ±1000ms),每行仅配对一次。
- 分词对齐:逐词文档的词吃掉文本中截至该词末尾字符的文本,空白与标点并入前一个词,使得音节拼接后与原排版文本完全一致。
- 对齐失败保护:整行文本无法匹配时,放弃该行逐词拆分并保留原行级状态,绝不产生部分贴合的半残行。
- 成功后行变体升级为
Syllable/FullSyllable,原有分边、子行与翻译完整保留。
use lyrics_helper::helpers::word_timing::apply_word_timings;
use lyrics_helper::{LineInfo, SyllableInfo};
let mut rows = vec![LineInfo::new_line(
"Ugh, you're a monster".to_string(),
Some(90),
Some(2160),
)];
let words = vec![LineInfo::new_syllable(vec![
SyllableInfo::new("Ugh".to_string(), 90, 420).into(),
SyllableInfo::new("you're ".to_string(), 420, 690).into(),
SyllableInfo::new("a ".to_string(), 690, 960).into(),
SyllableInfo::new("monster".to_string(), 960, 2160).into(),
])];
apply_word_timings(&mut rows, &words);
let syllables = rows[0].syllables().expect("对齐成功转为音节行");
assert_eq!(syllables[0].text(), "Ugh, "); // 标点与空格自动附着
assert_eq!(rows[0].text_from_any(), "Ugh, you're a monster");对应上游 Helpers/Optimization 中的各项规整算法:
| 子模块 | 核心函数 | 功能 |
|---|---|---|
syllable_word_merger |
merge(line) |
合并连续音节为同一单词(FullSyllableInfo),保留各自时间 |
apple_music |
prepare_lyrics(lines) / capitalization_normalization(lines)
|
音节修剪、同词合并、翻译冗余清洗及大小写规整 |
info_lines |
check_info_lines(lines, track_info) / is_info_line
|
识别作词/作曲/编曲等信息署名行及版权声明 |
musixmatch |
standardize_musixmatch_lyrics(lines) |
合并独立空白片段并规整 richsync 时间 |
sync_downgrade |
downgrade_to_line_synced(lines) |
逐字音节降级为纯逐行歌词 |
yrc |
standardize_yrc_lyrics(lines) |
移除末尾无意义空音节,清理网易云 YRC 冗余标记 |
explicit |
clean(str, strong) / fix_explicit(str)
|
脏词过滤及星号形式原词还原 |