如何在D中读取一条线作为范围?
我知道D中有范围,但我只是想知道如何使用这个概念简单地迭代字符串的每个字符?
为了展示我的目标,Go中的类似代码是:
for _, someChar := range someString {
// Do something
}
Run Code Online (Sandbox Code Playgroud)
Jon*_*vis 12
这取决于您是否要迭代代码单元或代码点.语言本身通过数组元素迭代数组,而字符串是代码单元的数组,所以如果你只是使用foreach类型推断,那么
foreach(c; "La Verité")
writeln(c);
Run Code Online (Sandbox Code Playgroud)
打印的最后两个字符将是乱码,因为é是由两个UTF-8代码单元组成的代码点,并且您打印出单独的代码单元(因为char是UTF-8代码单元).然而,如果你这样做
foreach(dchar c; "La Verité")
writeln(c);
Run Code Online (Sandbox Code Playgroud)
然后运行时将代码单元解码为代码点,并将é打印为最后一个字符.但这些都不是作为范围在字符串上运行.foreach无需使用输入范围API即可在本机上运行.但是,对于所有字符串类型,范围API看起来像
@property bool empty();
@property dchar front();
void popFront();
Run Code Online (Sandbox Code Playgroud)
它作为范围的字符串操作dchar- 而不是它们的代码单元类型.这避免了std.algorithm.filter在单个代码单元上运行等功能的问题,因为这没有任何意义.在代码点上操作也不是100%正确,因为Unicode在组合代码点和字形等方面变得非常复杂,但是在代码点上操作更接近于正确(并且我相信在增加范围方面正在进行工作)支持字形到标准库中,以满足您需要并且愿意支付性能的情况).因此,让字符串的范围API对它们进行操作dchar是非常正确的,如果你做了类似的事情
foreach(c; filter!"true"("La Verité"))
writeln(c);
Run Code Online (Sandbox Code Playgroud)
你会迭代dchar,并将é正确打印.所有这一切的缺点当然是foreach默认情况下字符串操作在代码单元级别,而字符串的范围API作为代码点操作它们,因此在混合数组操作和基于范围的操作时必须小心在字符串上.这也是为什么string并且wstring不被认为是随机访问范围 - 只是双向范围.当代码点由不同数量的代码单元组成时,你不能在代码点上对O(1)进行随机访问(而dstring 对于随机访问范围,因为使用UTF-32,每个代码单元都是代码点) .