D语言中的字符串分割

3

我正在学习D语言并尝试拆分字符串:

   import std.stdio;
   import std.string;

    auto file = File(path, "r"); 
    foreach (line; file.byLine) {
           string[] parts = split(line);

这段代码无法通过编译,报错如下:
Error: cannot implicitly convert expression (split(line)) of type char[][] to string[]

这个可以工作:

    auto file = File(path, "r"); 
    foreach (line; file.byLine) {
           char[][] parts = split(line);

但是为什么我必须使用char[][]呢?据我所了解,文档中说split返回一个string[],我更喜欢这个。

2个回答

5

使用 split(line.idup);

split 是一个模板函数,其返回类型取决于其参数。 file.byLine.front 返回一个 char[],出于性能考虑也会被重复使用。因此,如果需要当前循环迭代后的部分,则需要执行dupidup,具体取决于您的需要。


idup 创建一个数组的不可变副本。因此,如果这很关键,您可以随时转换为不可变类型,如果需要的话。例如:foreach (line; file.byLine.map!"cast(string)a") 使用 std.algorithm 中的 map。但是,要小心使用不可变类型转换。 - Sebastian Graf
2
除非你确实知道自己在做什么,否则不应该强制转换不可变对象。这样做会破坏类型系统,并可能导致意外行为。在这个例子中,跨循环迭代存储字符串可能会导致它们“改变值”,因为它们仍然指向byLine使用的同一临时缓冲区。 - Vladimir Panteleev
1
是的,但在一般情况下是需要的。D语言通常使用切片到原始字符串,所以如果没有idup,你就不会进行任何分配,而idup则进行了分配。然而,如果你需要在循环迭代中使用字符串,你必须对它进行复制(dup)或内存映射操作(idup),因为byLine会反复重用同一个缓冲区。如果你不需要所有拆分的部分,你可能只想复制你需要的部分。例如,如果你只需要第一部分,可以使用split(line).front.idup。 - robert

0
你可以使用 std.stdio.lines。根据你在 foreach 循环中输入变量的方式,它会为每次迭代分配一个新的缓冲区或重用旧的缓冲区。这样你就可以节省 .dup/.idup
然而,选择哪种类型取决于你的使用情况(即需要数据多长时间)。
foreach(string line; lines(file)) { // new string every iteration }

foreach(char[] line; lines(file)) { // reuse buffer } 

使用 ubyte 代替 char 将禁用 utf8 验证。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接