简体   繁体   English

TCL - 读取文件,额外行

[英]TCL - read a file, extra line

I have written the script below, and for some reason it output an extra 3rd line (top out.txt & name ).我写了下面的脚本,出于某种原因它 output 额外的第 3 行(top out.txt & name)。 How do I stop it from outputing the last 2 line to the output file.如何阻止它输出最后 2 行到 output 文件。

I think is because of this line but not too sure: set lines [split [read $list] "\n"]我认为是因为这一行但不太确定:set lines [split [read $list] "\n"]

Input put file - a.txt
**********************
abc
bcd

Output
*******
top out.txt 
name abc 
top out.txt 
name bcd 
top out.txt 
name 

set outfile      [open "out.txt" w]
set list         [open "a.list" r]
set dir         "[glob a.txt]"

    foreach ddd $dir {
        set lines [split [read $list] "\n"]
        foreach line $lines {
                puts $outfile "top $dir"
                puts $outfile "name $line"
        }
    }
close $list
close $outfile

The core of the issue is that split works with field separators and not field terminators;问题的核心是split使用字段分隔符而不是字段终止符; this is where you see the difference between the two.这就是您看到两者之间区别的地方。

If we look at the characters of your file, we'll see this: a b c \n b c d \n .如果我们查看文件的字符,我们会看到: a b c \n b c d \n (Technically, the \n might instead be \r \n or \r ; Tcl auto-adapts to that by default for text files.) If we split those characters at the \n , we get these substrings: abc , bcd , and the empty string for the characters after that final \n . (从技术上讲, \n可能改为\r \n\r ;对于文本文件,默认情况下 Tcl 会自动适应它。)如果我们在\nsplit这些字符,我们会得到这些子字符串: abcbcd最后一个\n之后的字符的空字符串 This means that when we join the strings with \n (as the joiner string) between all the elements, we get the original string back again.这意味着当我们在所有元素之间使用\n (作为join字符串)连接字符串时,我们会再次得到原始字符串。


You've got a few options for dealing with this.你有几个选择来处理这个问题。 My favourite is to add code to ignore blank lines;我最喜欢的是添加代码来忽略空行; versions of this are particularly useful for all sorts of human-written lists (as it's fairly easy to also add in comment skipping):这个版本对于各种人工编写的列表特别有用(因为添加注释跳过也相当容易):

    set lines [split [read $list] "\n"]
    foreach line $lines {
        if {$line eq ""} continue
        puts $outfile "top $dir"
        puts $outfile "name $line"
    }

Another option is to use the -nonewline option to read to discard that final \n :另一种选择是使用-nonewline选项read以丢弃最后的\n

    set lines [split [read -nonewline $list] "\n"]
    foreach line $lines {
        puts $outfile "top $dir"
        puts $outfile "name $line"
    }

You could also string trimright before splitting, but that would strip multiple newlines from the end (if they're present).您也可以在拆分之前将string trimright ,但这会从末尾去除多个换行符(如果它们存在)。

    set lines [split [string trimright [read $list] "\n"] "\n"]
    foreach line $lines {
        puts $outfile "top $dir"
        puts $outfile "name $line"
    }

Finally, if you're using a machine-generated list, you could consider just getting that code to not put a newline at the end.最后,如果您使用的是机器生成的列表,您可以考虑只让该代码不在末尾放置换行符。 Sometimes that's the easiest option of all.有时这是最简单的选择。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM