rust - 解决Rust字符串格式化程序时忽略某些Unicode字符串的正确字符串长度的问题

标签 rust

我正在使用println!使用以下命令排列列:

fn main() {
    let name_col_w = 24;
    let col_w = 9;

    println!("{:<0name_col_w$}{:<0col_w$}",
    "COL A",
    "COL B",
    name_col_w=name_col_w,
    col_w=col_w,
    
    );
    
    println!("{:<0name_col_w$}{:<0col_w$}",
    "000",
    "OOO",
    name_col_w=name_col_w,
    col_w=col_w,
    );    
    
    println!("{:<0name_col_w$}{:<0col_w$}",
    "麒麟24",
    "OOO",
    name_col_w=name_col_w,
    col_w=col_w,
    );
}
输出:
COL A                   COL B    
000                     OOO      
麒麟24                    OOO 
请注意,Unicode字符正被推到列的边界之外(第二列未全部对齐)。但是,字符串的长度小于限制(24)。
extern crate unicode_width;
use unicode_width::UnicodeWidthStr;

println!("{}","麒麟24".len()); // 8
println!("{}","麒麟24".chars().count()); // 4
println!("{}", UnicodeWidthStr::width("麒麟24")); // 6
看起来Rust格式语法实现错误地测量了宽度,因为字符串应该能够容纳在分配的24宽度之内。
有没有办法使 rust 识别正确的字符串宽度并正确设置其格式?还是我只是在做一些根本错误的事情?
(工作示例here)
我正在使用rust docs的字符串格式语法。

最佳答案

从技术上讲,这里没有不正确的字符串长度。
问题是大多数等宽字体根本不处理CJK,要么不支持CJK(因此退回到其他方面,这很可能是真的),要么相对于CJK不等宽:等宽的整个方面字体是

[all] letters and characters occupy the same amount of horizontal space


但这显然不是这种情况,因为您自己的对齐方式清楚地表明麒麟占用的水平空间大于3个ascii字符:
"麒麟",
"OOO",
因此,虽然麒麟24是4个字符[0],但它占用的视觉空间比5多一点,因此填充到24 [0]会导致对齐失败。
除了使用足够完整的等宽字体以在您期望的整个字符范围内都是等宽字体,或者使用GUI工具包(不受此问题影响)之外,我认为没有其他解决方案。我不确定,即使TUI/原始终端输出也可以解决此问题。
实际上,这甚至可能是GUI中的问题,因为如果您真的想使所有事情都正确,则需要遍历整个渲染管道,然后测量实际的“位图”大小(实际在屏幕上显示的大小)。
在POSIX 2001中,wcwidth(3)wcswidth(3)可以帮助查询终端以了解字符或字符串的宽度,这取决于终端是否有效,并且在实际终端中工作的可能性很小(例如,在我的实际终端机中,麒麟正好占据了4个单元,使用SO所使用的任何字体集显然都不是这种情况)。
[0]您可能遇到的另一个问题是count以及根据代码点进行字符串填充的工作,由于例如结合代码点,即使仅使用美国英语中可能遇到的形式,也可以轻松证明这一点:
println!("[{:<4}]", "é");
println!("[{:<4}]", "e\u{0301}");
输出
[é   ]
[é  ]
因为第二行针对单个音素簇使用两个代码点,这简化了对齐的计算(它增加了2个空间码点以达到4,除了前两个码点转换为单个音素簇,因此我们以3个音素簇结尾而不是我们期望的4)

关于rust - 解决Rust字符串格式化程序时忽略某些Unicode字符串的正确字符串长度的问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/65821654/

相关文章:

arrays - 如何在iter的位置方法中访问索引?

rust - 动态推断字符串的类型

rust - 理解 &type + 'a 语法

multidimensional-array - 转换 [[T; 的最佳方法是什么? 4]; 3] 变成 [T; 12]?

rust - rltk vga 字体显示不正确

python - 如何使用 PyO3 解码 PyCodeObject?

c - 在 Rust 中声明一个结构或变量的正确方法是什么,它可以传递给需要指针的 C 代码?

functional-programming - Rust 是否/将支持函数式编程习惯用法?

pattern-matching - 如何匹配具有常量值的结构中的字符串?

oop - 当特征需要的状态多于结构中包含的状态时,如何为结构实现特征?