从文件中拆分一行以替换 tcl 中的元素
Split a line from a file to replace elements in tcl
我正在尝试执行以下操作:
- 打开文件进行阅读
- 分割线
- 确定兴趣线
- 将名称
Prefix_2
替换为 Prefix_999
- 删除所有包含
Prefix_1
的行
- 将行保存到原始文件
我最多可以做到第 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
您可以根据自己的目的使用 regsub
。
% set line {Prefix_2.Var1 = 5124}
Prefix_2.Var1 = 5124
% regsub {Prefix_2} $line {Prefix_999}
Prefix_999.Var1 = 5124
%
由于您不是在编写文本过滤器,因此最好在更高级别上工作。
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 的配套库。
我在这里使用你的规范,因为你的代码有点难以理解。
- 打开文件进行阅读
- 分割线
- 确定兴趣线
- 将名称 Prefix_2 替换为 Prefix_999
- 删除所有包含Prefix_1
的行
- 将行保存到原始文件
确定兴趣线
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
的版本
行处理命令不必直接访问行缓冲区;相反,它可以简单地 return 行(跳过的行是空字符串)。在这种情况下,需要在 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 package, if, join, lappend, package, proc, regsub, set, switch, upvar
我正在尝试执行以下操作:
- 打开文件进行阅读
- 分割线
- 确定兴趣线
- 将名称
Prefix_2
替换为Prefix_999
- 删除所有包含
Prefix_1
的行
- 将行保存到原始文件
我最多可以做到第 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
您可以根据自己的目的使用 regsub
。
% set line {Prefix_2.Var1 = 5124}
Prefix_2.Var1 = 5124
% regsub {Prefix_2} $line {Prefix_999}
Prefix_999.Var1 = 5124
%
由于您不是在编写文本过滤器,因此最好在更高级别上工作。
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 的配套库。
我在这里使用你的规范,因为你的代码有点难以理解。
- 打开文件进行阅读
- 分割线
- 确定兴趣线
- 将名称 Prefix_2 替换为 Prefix_999
- 删除所有包含Prefix_1 的行
- 将行保存到原始文件
确定兴趣线
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
行处理命令不必直接访问行缓冲区;相反,它可以简单地 return 行(跳过的行是空字符串)。在这种情况下,需要在 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 package, if, join, lappend, package, proc, regsub, set, switch, upvar