Rust语言标签处理库langtag的使用,高效解析与验证BCP 47语言标签格式
Rust语言标签处理库langtag的使用,高效解析与验证BCP 47语言标签格式
这个crate提供了对RFC5646(BCP47)定义的语言标签的实现。
使用方法
你可以轻松地从任何字符串解析新的语言标签:
use langtag::LangTag;
fn main() -> Result<(), langtag::InvalidLangTag<&'static str>> {
let tag = LangTag::new("fr-FR")?;
assert_eq!(tag.language().unwrap().primary(), "fr");
assert!(tag == "Fr-fr"); // 比较是大小写不敏感的
Ok(())
}
请注意LangTag::new
不会复制给定的数据,而是仅仅借用它。LangTagBuf
类型允许你拥有语言标签的所有权。一旦解析完成,你可以使用提供的函数探索语言标签的每个组成部分。
完整示例代码
以下是使用langtag库处理语言标签的更完整示例:
use langtag::{LangTag, LangTagBuf};
fn main() {
// 示例1:基本解析和验证
match LangTag::new("en-US") {
Ok(tag) => {
println!("Primary language: {}", tag.language().unwrap().primary());
println!("Region: {}", tag.region().unwrap());
}
Err(e) => println!("Invalid language tag: {}", e),
}
// 示例2:拥有所有权的LangTagBuf
let tag_buf = LangTagBuf::new("zh-CN").unwrap();
println!("Chinese Simplified: {}", tag_buf);
// 示例3:比较操作(大小写不敏感)
let tag1 = LangTag::new("en-US").unwrap();
let tag2 = LangTag::new("EN-us").unwrap();
assert!(tag1 == tag2);
// 示例4:提取所有组件
if let Ok(tag) = LangTag::new("de-Latn-DE-1996") {
println!("Language: {}", tag.language().unwrap());
if let Some(script) = tag.script() {
println!("Script: {}", script);
}
if let Some(region) = tag.region() {
println!("Region: {}", region);
}
if let Some(variant) = tag.variant() {
println!("Variant: {}", variant);
}
}
}
完整示例demo
基于上述示例,这里提供一个更全面的使用demo:
use langtag::{LangTag, LangTagBuf};
fn main() {
// 1. 创建语言标签
println!("--- 基本语言标签创建 ---");
let simple_tag = LangTag::new("en").unwrap();
println!("简单标签: {}", simple_tag);
// 2. 带区域的标签
let region_tag = LangTag::new("zh-CN").unwrap();
println!("带区域的标签: {}", region_tag);
// 3. 完整标签解析
println!("\n--- 完整标签解析 ---");
if let Ok(tag) = LangTag::new("sr-Latn-RS") {
println!("完整标签: {}", tag);
println!("主语言: {}", tag.language().unwrap().primary());
println!("书写系统: {}", tag.script().unwrap());
println!("地区: {}", tag.region().unwrap());
}
// 4. 标签比较
println!("\n--- 标签比较 ---");
let tag1 = LangTag::new("en-US").unwrap();
let tag2 = LangTag::new("en-us").unwrap();
println!("比较结果: {}", tag1 == tag2); // true
// 5. 创建拥有所有权的标签
println!("\n--- 拥有所有权的标签 ---");
let owned_tag = LangTagBuf::new("fr-FR").unwrap();
println!("法语(法国): {}", owned_tag);
// 6. 错误处理
println!("\n--- 错误处理 ---");
match LangTag::new("invalid-tag") {
Ok(tag) => println!("有效标签: {}", tag),
Err(e) => println!("错误: {}", e),
}
// 7. 复杂标签处理
println!("\n--- 复杂标签处理 ---");
if let Ok(tag) = LangTag::new("hy-Latn-IT-arevela") {
println!("复杂标签: {}", tag);
println!("变体: {}", tag.variant().unwrap());
}
}
许可证
采用以下任一许可证:
- Apache License, Version 2.0
- MIT license
贡献
除非您明确声明,否则根据Apache-2.0许可证定义,您有意提交的任何贡献将被视为双重许可如上所述,不附加任何其他条款或条件。
1 回复
Rust语言标签处理库langtag的使用:高效解析与验证BCP 47语言标签格式
介绍
langtag
是Rust中一个专门用于处理BCP 47语言标签的库。BCP 47是定义语言标签格式的标准,用于标识人类语言、脚本、地区等信息,常见于国际化应用中。
该库提供:
- 完整的BCP 47语言标签解析
- 严格的格式验证
- 便捷的组件访问方法
- 符合RFC 5646和RFC 4647标准
安装
在Cargo.toml中添加依赖:
[dependencies]
langtag = "0.3"
基本用法
解析语言标签
use langtag::LanguageTag;
fn main() {
// 解析en-US语言标签
let tag: LanguageTag = "en-US".parse().unwrap();
// 输出主要语言
println!("Primary language: {}", tag.primary_language());
// 输出地区(如果有)
if let Some(region) = tag.region() {
println!("Region: {}", region);
}
}
验证语言标签
use langtag::LanguageTag;
// 验证语言标签是否有效
fn is_valid_tag(tag_str: &str) -> bool {
tag_str.parse::<LanguageTag>().is_ok()
}
fn main() {
// 验证中文标签
println!("{}", is_valid_tag("zh-Hant-CN")); // true
// 验证无效标签(USA不是有效地区代码)
println!("{}", is_valid_tag("en-USA")); // false
}
高级用法
构建语言标签
use langtag::{LanguageTag, Subtag};
fn main() {
// 创建新的语言标签
let mut tag = LanguageTag::new();
// 设置主要语言
tag.set_primary_language("zh").unwrap();
// 设置脚本
tag.set_script("Hant").unwrap();
// 设置地区
tag.set_region("TW").unwrap();
// 输出构建的标签: zh-Hant-TW
println!("{}", tag);
}
比较语言标签
use langtag::LanguageTag;
fn main() {
// 解析两个相似但不完全相同的标签
let tag1: LanguageTag = "en-US".parse().unwrap();
let tag2: LanguageTag = "en-Latn-US".parse().unwrap();
// 基本匹配比较(忽略次要差异)
println!("{}", tag1.matches(&tag2)); // true
// 严格相等比较
println!("{}", tag1 == tag2); // false
}
处理扩展和私有部分
use langtag::LanguageTag;
fn main() {
// 解析包含扩展的语言标签
let tag: LanguageTag = "de-Latn-DE-u-attr-co-phonebk".parse().unwrap();
// 输出脚本信息
println!("Script: {:?}", tag.script());
// 输出所有扩展
println!("Extensions: {:?}", tag.extensions());
// 输出第一个扩展的单字符标识
if let Some(ext) = tag.extensions().next() {
println!("First extension: {}", ext.singleton());
}
}
实际应用示例
语言标签过滤
use langtag::LanguageTag;
// 根据过滤条件筛选语言标签
fn filter_tags(tags: Vec<&str>, filter: &str) -> Vec<String> {
let filter_tag: LanguageTag = filter.parse().unwrap();
tags.into_iter()
.filter_map(|t| t.parse::<LanguageTag>().ok())
.filter(|t| t.matches(&filter_tag))
.map(|t| t.to_string())
.collect()
}
fn main() {
let tags = vec!["en-US", "en-GB", "fr-FR", "es-ES"];
// 筛选所有英文标签
let filtered = filter_tags(tags, "en");
println!("{:?}", filtered); // ["en-US", "en-GB"]
}
最佳语言匹配
use langtag::{LanguageTag, LangugeTagFilter};
// 在支持的语言中找到与请求最匹配的语言
fn find_best_match(supported: &[&str], requested: &str) -> Option<String> {
let requested_tag: LanguageTag = requested.parse().ok()?;
let supported_tags: Vec<LanguageTag> = supported.iter()
.filter_map(|s| s.parse().ok())
.collect();
requested_tag.best_match(supported_tags.iter())
.map(|t| t.to_string())
}
fn main() {
let supported = ["zh-CN", "zh-TW", "en-US"];
// 查找中文香港的最佳匹配
println!("{:?}", find_best_match(&supported, "zh-HK")); // Some("zh-TW")
// 查找法语(不支持)的匹配
println!("{:?}", find_best_match(&supported, "fr-FR")); // None
}
完整示例:国际化应用中的语言处理
use langtag::{LanguageTag, LangugeTagFilter};
use std::collections::HashMap;
fn main() {
// 模拟应用支持的语言资源
let resources: HashMap<String, &str> = [
("en-US".to_string(), "Hello!"),
("en-GB".to_string(), "Hello!"),
("zh-CN".to_string(), "你好!"),
("zh-TW".to_string(), "你好!"),
("ja-JP".to_string(), "こんにちは!"),
].iter().cloned().collect();
// 用户偏好语言列表(按优先级排序)
let user_preferences = ["zh-HK", "en-US", "fr-FR"];
// 找到最佳匹配的语言
let supported_langs: Vec<&str> = resources.keys().map(|s| s.as_str()).collect();
if let Some(best_match) = find_best_match(&supported_langs, &user_preferences.join(",")) {
println!("最佳匹配语言: {}", best_match);
println!("显示内容: {}", resources[&best_match]);
} else {
println!("没有匹配的语言,使用默认英语");
println!("显示内容: {}", resources["en-US"]);
}
}
// 扩展的最佳匹配函数,处理多个偏好语言
fn find_best_match(supported: &[&str], requested: &str) -> Option<String> {
for lang in requested.split(',') {
let requested_tag: LanguageTag = match lang.parse() {
Ok(tag) => tag,
Err(_) => continue,
};
let supported_tags: Vec<LanguageTag> = supported.iter()
.filter_map(|s| s.parse().ok())
.collect();
if let Some(matched) = requested_tag.best_match(supported_tags.iter()) {
return Some(matched.to_string());
}
}
None
}
注意事项
- 解析失败时会返回
Err
,应妥善处理错误情况 - 语言标签比较有
matches
(基本匹配)和==
(严格相等)两种方式 - 构建语言标签时,组件顺序必须符合BCP 47规范
- 地区代码应使用ISO 3166-1 alpha-2,脚本代码应使用ISO 15924
langtag
库为Rust中处理语言标签提供了完整且符合标准的解决方案,适合需要国际化支持的应用程序使用。