从文件中拆分一行以替换tcl中的元素

时间:2016-03-26 11:23:50

标签: regex tcl

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

  1. 打开文件阅读
  2. 分割线
  3. 识别感兴趣的行
  4. 将姓名Prefix_2替换为Prefix_999
  5. 删除Prefix_1
  6. 的所有行
  7. 将行保存到原始文件
  8. 我可以做到第3点但是当涉及到替换名称时,我似乎无法将感兴趣的线分成元素,以便我可以用Prefix_2替换Prefix_999

    它总是取代整个感兴趣的行,如下所示,例如

    Prefix_2.Var1 = 5124将替换为Prefix_999而不是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
    

2 个答案:

答案 0 :(得分:1)

由于您没有编写文本过滤器,因此最好在更高级别上工作。

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的伴随库。

我在这里使用您的规范,因为您的代码有点难以理解。

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

    processLine命令将接收参数line中的每一行。 switch -regexp $line {...}命令允许我按行前缀(或者不管怎样,标准可以是正则表达式可以表达的任何内容)对行进行分类。有三类线:以" Prefix_1"开头的那些,以" Prefix_2"开头的那些和所有其他线。我将它设置为一个默认操作,将行保存在持久缓冲区中(在命令中称为buf,在其外部$bufName:在我的代码中,两个名称都相同)。

    将Prefix_2名称替换为Prefix_999

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

    删除所有包含Prefix_1的行

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

    打开文件阅读拆分行

    这由fileutil::foreachLine自动完成。

    将行保存到原始文件

    我只是使用换行符加入缓冲区中的行并调用fileutil::writeFile来更新文件。

    ETA 没有upvar

    的版本

    行处理命令不必直接访问行缓冲区;相反,它可以简单地返回行(跳过的行是空字符串)。在这种情况下,需要在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]
    

    (我将这个版本评为劣等。)

    文档:fileutil包,ifjoinlappendpackageprocregsub,{{ 3}},setswitch

答案 1 :(得分:0)

您可以将regsub用于您的目的。

% set line {Prefix_2.Var1 = 5124}           
Prefix_2.Var1 = 5124 
% regsub {Prefix_2} $line {Prefix_999} 
Prefix_999.Var1 = 5124
%