从文件中拆分一行以替换 tcl 中的元素 [英] Split a line from a file to replace elements in tcl

查看:36
本文介绍了从文件中拆分一行以替换 tcl 中的元素的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试执行以下操作:

I'm trying to do the following:

  1. 打开文件读取
  2. 分割线
  3. 确定感兴趣的线路
  4. 将名称 Prefix_2 替换为 Prefix_999
  5. 删除所有带有 Prefix_1
  6. 的行
  7. 将行保存到原始文件

我最多可以做第 3 点,但是在替换名称时,我似乎无法将感兴趣的行拆分为元素,以便我可以用 Prefix_999 替换 Prefix_2>

I can do up to point 3 but when it comes to replacing the names I cant seem to split the line of interest into elements so that I can replace Prefix_2 with Prefix_999

它总是替换为整个感兴趣的行,如下所示,例如

It always replaces with entire line of interest as shown below e.g.

Prefix_2.Var1 = 5124 将替换为 Prefix_999 而不是 Prefix_999.Var1 = 5124

Prefix_2.Var1 = 5124 will replace to Prefix_999 rather than Prefix_999.Var1 = 5124

文件Data.txt

Prefix_1.Var1 = 200
Prefix_1.Var2 = 0.3
Prefix_1.Var3 = 0.5
Prefix_1.Var4 = 0.25
Prefix_1.Var5 = 3
Prefix_1.Var6 = 36
Prefix_1.Var7 = 5612
Prefix_1.Var8 = 631
Prefix_1.Var9 = 102
Prefix_1.Var10 = 14
Prefix_1.Var11 = 3
Prefix_1.Var12 = 2
Prefix_2.Var1 = 5124
Prefix_2.Var2 = 876
Prefix_2.Var3 = 10.1
Prefix_2.Var4 = 11

我的代码:

set input [open "Data.txt" r]

set number 0
set var2 ""
while { [gets $input line] >= 0 } {
    incr number
    set sline [split $line "\n"]
    set var1 [regexp {Prefix_2.Var1} $sline match]
    if {$var1 == 1} {
        set rVar1 [split $sline \s]
        # check the length to index correctly for replacing
        set rVar2 [llength $rVar1]
        set rVar2 [lreplace $rVar2 0 0 Prefix_999.Var1]
    }
}

close $input

推荐答案

由于您不是在编写文本过滤器,因此最好在更高级别上工作.

Since you're not writing a text filter, you might be better off working on a higher level.

proc processLine {bufName line} {
    upvar 1 $bufName buf
    switch -regexp $line {
        {^Prefix_1\.} {}
        {^Prefix_2\.} {
            lappend buf [regsub 2 $line 999]
        }
        default {
            lappend buf $line
        }
    }
}

package require fileutil

set buf {}
fileutil::foreachLine line data.txt {
    processLine buf $line
}
fileutil::writeFile data.txt [join $buf \n]

较低级别的open-gets-close 组合是语言核心的一部分;fileutil 包可以用来抽象出这个组合的大多数用法,它是 Tcllib 的一部分,Tcl 的配套库.

The lower-level open-gets-close combo is part of the language core; the fileutil package that can be used to abstract away most usages of this combo is a part of Tcllib, the companion library for Tcl.

我正在这里处理您的规范,因为您的代码有点难以理解.

I'm working with your specification here, since your code is a little hard to follow.

  1. 打开文件读取
  2. 分割线
  3. 确定感兴趣的线路
  4. 用 Prefix_999 替换 Name Prefix_2
  5. 删除所有带有 Prefix_1 的行
  6. 将行保存到原始文件

确定兴趣线

processLine 命令将接收参数line 中的每一行.switch -regexp $line {...} 命令让我可以通过前缀(或其他任何方式,标准可以是任何可以用正则表达式表达的东西)对行进行分类.行分为三类:以Prefix_1"开头的行、以Prefix_2"开头的行以及所有其他行.我将在持久缓冲区中保存行作为默认操作(在命令内部称为 buf,在命令外部称为 $bufName:在我的代码中,两个名称相同).

The processLine command will be receiving each line in the parameter line. The switch -regexp $line {...} command lets me classify the lines, by prefix (or by whatever, the criteria can be anything that can be expressed by a regular expression). There are three classes of lines: those that start with "Prefix_1", those that start with "Prefix_2", and all other lines. I make it a default action to save lines in a persistent buffer (which is called buf inside the command and $bufName outside it: in my code both names are the same).

用 Prefix_999 替换 Name Prefix_2

对于以Prefix_2"开头的行,我跳过默认操作,而是保存修改后的行,其中第一次出现的 2 被 999 替换.

For lines that start with "Prefix_2", I skip the default action and instead save a modified line where the first occurrence of 2 is replaced by 999.

删除所有带有 Prefix_1 的行

只需跳过这些行的默认操作即可满足此要求.

This requirement is fulfilled simply by skipping the default action for these lines.

打开文件读取分割线

这是由 fileutil::foreachLine 自动完成的.

This is done automatically by fileutil::foreachLine.

将行保存到原始文件

我只是将缓冲区中的行与换行符连接起来,然后调用 fileutil::writeFile 来更新文件.

I simply join the lines in the buffer with newline characters and invoke fileutil::writeFile to update the file.

ETA 没有 upvar

行处理命令不必直接访问行缓冲区;相反,它可以简单地返回行(跳过的行是空字符串).在这种情况下,需要在 foreachLine 的脚本参数中组装行缓冲区:

The line processing command doesn't have to access the line buffer directly; instead it can simply return lines (skipped lines being empty strings). In this case assembling the line buffer needs to be performed in the script argument to foreachLine:

proc processLine line {
    switch -regexp $line {
        {^Prefix_1\.} {}
        {^Prefix_2\.} {
            regsub 2 $line 999
        }
        default {
            return $line
        }
    }
}

package require fileutil

set buf {}
fileutil::foreachLine line data.txt {
    set line [processLine $line]
    if {$line ne {}} {
        lappend buf $line
    }
}
fileutil::writeFile data.txt [join $buf \n]

(我认为这个版本较差.)

(I'd rate this version as inferior.)

文档:fileutil 包的程序,if, join, lappend, , proc, regsub, 设置, switch, upvar

Documentation: fileutil package, if, join, lappend, package, proc, regsub, set, switch, upvar

这篇关于从文件中拆分一行以替换 tcl 中的元素的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆