Rust国际化域名处理库idna_mapping的使用,支持Unicode和IDNA2008标准的高效域名转换
idna_mapping
此crate不直接使用。它是unicode-rs后端的一部分,用于idna
crate,提供UTS 46映射数据和对JoiningType数据的抽象(委托给unicode-joining-type
)。
请参阅最新版本的idna_adapter
crate的README以了解如何使用。
许可证
(Apache-2.0 OR MIT) AND Unicode-3.0
此crate中的Unicode数据遵循Unicode-3.0,其余部分遵循Apache-2.0 OR MIT。
安装
运行以下Cargo命令在您的项目目录中:
cargo add idna_mapping
或者将以下行添加到您的Cargo.toml:
idna_mapping = “1.1.0”
所有者
Manish Goregaokar Henri Sivonen Valentin Gosu
类别
国际化 (i18n) 无标准库
完整示例代码:
// 注意:根据提供的内容,idna_mapping crate不直接使用
// 以下是使用idna crate的示例,idna_mapping作为其依赖
use idna;
fn main() {
// 示例:将Unicode域名转换为ASCII兼容编码(ACE)
let unicode_domain = "例子.测试";
match idna::Config::default()
.use_std3_ascii_rules(true)
.to_ascii(unicode_domain)
{
Ok(ascii_domain) => {
println!("Unicode域名: {}", unicode_domain);
println!("ACE编码: {}", ascii_domain);
}
Err(e) => {
println!("转换失败: {}", e);
}
}
}
// 另一个示例:验证和处理国际化域名
use idna;
fn validate_idna_domain(domain: &str) -> Result<String, idna::Errors> {
let config = idna::Config::default()
.use_std3_ascii_rules(true)
.verify_dns_length(true);
config.to_ascii(domain)
}
fn main() {
let test_domains = vec!["examplé.test", "测试.例子", "invalid..domain"];
for domain in test_domains {
match validate_idna_domain(domain) {
Ok(ace) => println!("有效: {} -> {}", domain, ace),
Err(e) => println!("无效: {} - 错误: {:?}", domain, e),
}
}
}
1 回复
Rust国际化域名处理库idna_mapping使用指南
概述
idna_mapping是一个遵循IDNA2008标准的Rust国际化域名处理库,提供Unicode域名与ASCII兼容编码(Punycode)之间的高效转换功能。
核心特性
- 完全支持IDNA2008标准
- 高性能Unicode域名处理
- 零依赖的纯Rust实现
- 完整的错误处理机制
安装方法
在Cargo.toml中添加依赖:
[dependencies]
idna_mapping = "0.1"
基本用法
域名编码(Unicode转ASCII)
use idna_mapping::Config;
fn main() {
let config = Config::default();
let unicode_domain = "例子.测试";
match config.to_ascii(unicode_domain) {
Ok(ascii_domain) => {
println!("ASCII编码结果: {}", ascii_domain);
// 输出: xn--fsq.xn--0zwm56d
}
Err(e) => eprintln!("编码错误: {}", e),
}
}
域名解码(ASCII转Unicode)
use idna_mapping::Config;
fn main() {
let config = Config::default();
let ascii_domain = "xn--fsq.xn--0zwm56d";
match config.to_unicode(ascii_domain) {
Ok(unicode_domain) => {
println!("Unicode解码结果: {}", unicode_domain);
// 输出: 例子.测试
}
Err(e) => eprintln!("解码错误: {}", e),
}
}
高级配置
自定义配置选项
use idna_mapping::{Config, TransitionalProcessing, UseStd3AsciiRules};
fn main() {
let config = Config::default()
.transitional_processing(TransitionalProcessing::Enabled)
.use_std3_ascii_rules(UseStd3AsciiRules::Enabled)
.verify_dns_length(true);
let result = config.to_ascii("münchen.example");
// 根据配置进行编码处理
}
批量处理域名
use idna_mapping::Config;
fn main() {
let config = Config::default();
let domains = vec!["例子.com", "测试.org", "münchen.de"];
for domain in domains {
match config.to_ascii(domain) {
Ok(encoded) => println!("{} -> {}", domain, encoded),
Err(e) => eprintln!("处理 {} 时出错: {}", domain, e),
}
}
}
错误处理
use idna_mapping::{Config, Error};
fn handle_domain_conversion(domain: &str) -> Result<String, Error> {
let config = Config::default();
config.to_ascii(domain)
}
fn main() {
let test_cases = ["valid.example", "invalid..example"];
for case in test_cases.iter() {
match handle_domain_conversion(case) {
Ok(result) => println!("成功: {}", result),
Err(Error::DomainTooLong) => eprintln!("错误: 域名过长"),
Err(Error::InvalidDomainLength) => eprintln!("错误: 无效域名长度"),
Err(Error::LabelTooLong) => eprintln!("错误: 标签过长"),
Err(e) => eprintln!("其他错误: {}", e),
}
}
}
性能优化建议
对于需要处理大量域名的场景:
use idna_mapping::Config;
use std::time::Instant;
fn main() {
let config = Config::default();
let domains: Vec<String> = (0..1000).map(|i| format!("测试{}.example", i)).collect();
let start = Instant::now();
for domain in &domains {
let _ = config.to_ascii(domain);
}
let duration = start.elapsed();
println!("处理1000个域名耗时: {:?}", duration);
}
完整示例demo
// 完整示例:国际化域名处理工具
use idna_mapping::{Config, Error, TransitionalProcessing, UseStd3AsciiRules};
use std::time::Instant;
fn main() {
println!("=== 国际化域名处理工具 ===");
// 创建默认配置
let default_config = Config::default();
// 创建自定义配置
let custom_config = Config::default()
.transitional_processing(TransitionalProcessing::Enabled)
.use_std3_ascii_rules(UseStd3AsciiRules::Enabled)
.verify_dns_length(true);
// 测试域名列表
let test_domains = vec![
"例子.测试",
"münchen.de",
"北京.中国",
"café.fr",
"测试域名.example.com"
];
println!("\n=== 基本编码解码测试 ===");
for domain in &test_domains {
println!("\n处理域名: {}", domain);
// 使用默认配置编码
match default_config.to_ascii(domain) {
Ok(encoded) => {
println!("编码结果: {}", encoded);
// 解码验证
match default_config.to_unicode(&encoded) {
Ok(decoded) => println!("解码验证: {}", decoded),
Err(e) => eprintln!("解码错误: {}", e),
}
}
Err(e) => eprintln!("编码错误: {}", e),
}
}
println!("\n=== 批量处理性能测试 ===");
let batch_domains: Vec<String> = (0..500)
.map(|i| format!("测试{}.example.com", i))
.collect();
let start_time = Instant::now();
let mut success_count = 0;
for domain in &batch_domains {
if default_config.to_ascii(domain).is_ok() {
success_count += 1;
}
}
let duration = start_time.elapsed();
println!("处理 {} 个域名,成功: {},耗时: {:?}",
batch_domains.len(), success_count, duration);
println!("\n=== 错误处理示例 ===");
let error_cases = [
"invalid..domain", // 连续的点
"a".repeat(64) + ".com", // 标签过长
"", // 空域名
];
for case in &error_cases {
match default_config.to_ascii(case) {
Ok(result) => println!("'{}' -> {}", case, result),
Err(Error::DomainTooLong) => eprintln!("'{}': 错误 - 域名过长", case),
Err(Error::InvalidDomainLength) => eprintln!("'{}': 错误 - 无效域名长度", case),
Err(Error::LabelTooLong) => eprintln!("'{}': 错误 - 标签过长", case),
Err(e) => eprintln!("'{}': 错误 - {}", case, e),
}
}
println!("\n=== 自定义配置测试 ===");
let special_domains = ["münchen.example", "straße.test"];
for domain in &special_domains {
println!("\n域名: {}", domain);
// 默认配置
match default_config.to_ascii(domain) {
Ok(result) => println!("默认配置: {}", result),
Err(e) => eprintln!("默认配置错误: {}", e),
}
// 自定义配置
match custom_config.to_ascii(domain) {
Ok(result) => println!("自定义配置: {}", result),
Err(e) => eprintln!("自定义配置错误: {}", e),
}
}
}
注意事项
- 确保输入的域名格式正确
- 处理用户输入时始终检查错误
- 考虑使用缓存机制处理重复域名
- 注意IDNA2008与旧标准的兼容性差异
这个库为处理国际化域名提供了完整且符合标准的解决方案,适合在需要支持多语言域名的网络应用中使用。