0

我有两个文件。

  • 归档一个

0 10 20 30

10 20 30 40

0 10 23 34

文件 a 的值是(x1 y1 x2 y2 格式)

  • 文件 b
  • 格式为 PMM xy -(某个数字)

PMM 10 20 -100

PMM 20 30 -150

PMM 50 60 -100

在文件 B 中,我想搜索字段 4,5(从 P 作为字段 1 开始)是否在文件 a 的范围内。如果是,则不打印 FileB 的行,否则打印该行。

我们不会打印文件 b 的行

x1 < x < x2 & y1 < y < y2

所以脚本的 O/P 应该是

文件 c

PMM 50 60 -100


我在 tcl 中编写了以下脚本,但我的问题是它没有在 File a 中搜索文件 b 的所有内容


set abc "b"
set ab "a"

set cord [open $ab "r"]

if [catch {open $abc r} FILE_R {
    puts "failed to read $abc"
    return -1
}

while { [gets $FILE_R line] >= 0 } {
    if [regexp {^#} $line ] {
    } else {
        set x_cord [lindex $line 3] 
        set y_cord [lindex $line 4]
        while { [gets $cord line] >= 0 } {
            set x1_cord [lindex $line 0]
            set y1_cord [lindex $line 1]
            set x2_cord [lindex $line 2]
            set y2_cord [lindex $line 3]

            if { [expr x1_cord < x_cord && x_cord < x2_cord && y1_cord < y_cord && y_cord < y2_cord ] == 1 } {
            } else {
                puts $line
            }
        }
    }
}

close $FILE_R
4

3 回答 3

1

这一行:

if { [expr x1_cord < x_cord && x_cord < x2_cord && y1_cord < y_cord && y_cord < y2_cord ] == 1 } {

如果在一些方面是相当错误的。特别是,这些变量没有被读取。您还可以通过放入条件来做额外的工作exprif因为它们已经使用相同的语法。相反,使用这个:

if {$x1_cord < $x_cord && $x_cord < $x2_cord && $y1_cord < $y_cord && $y_cord < $y2_cord} {

您似乎也在使用if {somecondition} {} else { somescript }; 这并不是特别低效,但看起来很奇怪。只需否定条件并这样做:if {!(somecondition)} { somescript }

于 2013-02-21T15:54:06.620 回答
0

这是我的解决方案:

package require Tclx

# Read file a.txt, which contains x1 y1 x2 y2
# After reading, coords will be
#     {{0 10 20 30} {10 20 30 40} {0 10 23 34}}
# which is a list of lists
set coords [split [read_file a.txt] \n]

# Read file b.txt, line by line
# where each line contains P M M x y -(some number)
for_file line b.txt {
    if {[regexp {^#} $line]} { continue }; # skip comment

    #lassign    $line p m1 m2 x y n; # parse the line into proper fields
    foreach {p m1 m2 x y n} $line {}; 
    set inrange 0; # assume out of range, will flag it if found otherwise
    foreach coord $coords {
        #lassign $coord x1 y1 x2 y2; # parse the range
            foreach {x1 y1 x2 y2} $coord {}
        if {$x1 < $x && $x < $x2 && $y1 < $y && $y < $y2} {
            set inrange 1; # we are in range, set the flag for not printing
        }
    }

    # Print if not in any range
    if {!$inrange} { puts $line }
}

讨论

  • 命令read_file,for_filelassign来自Tclx包,这大大简化了生活。从 Tcl 版本 8.5 开始,它lassign成为一个内置命令。
  • 回复评论:read_file只要你使用Tclx包就可以使用。您是否拥有 Tcl 8.4、8.5 或更高版本并不重要。
  • 其余的代码是直截了当的,我希望你没有理解困难。
  • 由于 user2095095 无权访问Tclx并且他/她正在运行 Tcl 8.4,因此我必须lassignforeach技巧替换。
于 2013-02-22T05:23:34.320 回答
0

首先打开坐标文件并读取每一行,直到获得 x1,y1,x2,y2 的最大值和最小值。那将是 8 个值。

然后打开第二个文件并读取每一行一次。然后将其拆分并与您的限制进行比较。

您上面遇到的问题是您打开每个文件一次,但每次您有一个 FILE_R 行时您都试图重新读取坐标文件。但是你永远不会回到文件的开头。如果你这样做了,它的效率会非常低,但可能会奏效。首先获取限制,然后处理第二个文件。

用正则表达式匹配行但用扫描分割它们也更聪明。这样,您就不太可能遇到 Tcl 认为重要的问题,例如左大括号或分号或过多的空格。例如:

% scan "P M M 10 20 -100" {P M M %d %d %d} x y z
3
% list $x $y $z
10 20 -100

请注意,我们可以检查我们获得了正确数量的扫描参数 (3)。

于 2013-02-21T12:34:58.453 回答