Tcl 如何将puts的输出作为输入提供给proc?

Tcl 如何将puts的输出作为输入提供给proc?,tcl,Tcl,我有一个将列表打印为格式化表的程序。这是一个像print_table$temp这样的用例 如果我使用“puts”命令打印输出作为proc print_表的输入,如何给出不同proc的输出 我想让下面的工作 > print_table [abc $list1] ============== | abc | 1 | | defg | 2 | | hijlk | 3 | | lmn | 4 | ============== 最简单的方法之一是临时替换put # P

我有一个将列表打印为格式化表的程序。这是一个像print_table$temp这样的用例

如果我使用“puts”命令打印输出作为proc print_表的输入,如何给出不同proc的输出

我想让下面的工作

> print_table [abc $list1]
 ==============
 | abc    | 1 |
 | defg   | 2 |
 | hijlk  | 3 |
 | lmn    | 4 |
 ==============

最简单的方法之一是临时替换
put

# Partial emulation of [puts] API; assumes we don't write to other files
proc capturing_puts {args} {
    global capturedStdout
    set value [lindex $args end]
    set args [lrange $args 0 end-1]
    if {"-nonewline" ni $args} {
        append value "\n"
    }
    append capturedStdout $value
}

# A helper procedure to install and restore the replacement [puts] implementation
proc capture {script} {
    global capturedStdout
    rename puts original_puts
    rename capturing_puts puts
    set capturedStdout ""

    try {
        uplevel 1 $script
    } finally {
        # Restore the original, even on error!
        rename puts capturing_puts
        rename original_puts puts
    }
    return $capturedStdout
}

# Now we can use it like this
set output [capture {
    abc $list1
}]
print_table $output
如果您可以使打印代码使用(可选)参数来指定要写入的通道,则更容易。然后,您根本不需要在输出捕获方面乱来



我认为可以使用通道转换来进行捕获,这比用稍微复杂的API(
put
)替换命令要简单得多,但是编写它们要复杂得多。

正如Donal指出的,打印代码最好使用通道作为参数。或者,如果您无法控制所有打印过程,或者您不想触碰它们,则使用通道拦截器(如前所述):

信道拦截器被实现为信道变换;以前也有报道过

步骤1:定义通道拦截器 上面的片段是直接从中派生出来的

步骤2:在打印代码周围使用
stdout
注册拦截器 您可以将拦截样板文件打包到
print\u table
,使其看起来像:
print\u table{abc$list1}

proc print_table {script} {
    # set up interception
    uplevel 1 $script
    # remove interception
}

@Donal,@Calivin先生,你的两个解决方案都接近我的预期。但它将所有数据打印在一个列中

建议的代码给出如下输出:

> print_table  [capture {abc $list1}]                    
 ========
 | abc   
 | 1     
 | defg  
 | 2     
 | hijlk 
 | 3     
 | lmn   
 | 4     
 ========
我已经输入了print_表的代码,可能是我可以添加proc print_表的详细信息,如果进行任何更改更有意义,我当前正在输入一个列表名。本可以有更好的方法来编写这个过程

proc print_table { table } {
    set col_len [llength [lindex $table 0]]
    for {set i 0} {$i < $col_len} { incr i } { set col_wid($i) 0 }
    foreach line $table {
        for {set i 0} {$i < $col_len} { incr i } { 
            set temp_col_width($i) [string length [lindex $line $i]];
            if { $col_wid($i) > $temp_col_width($i) } { set col_wid($i) $col_wid($i) } else { set col_wid($i) $temp_col_width($i) }
        }
    }
    set total_col 0; for {set i 0} {$i < $col_len} { incr i } { set total_col [expr $total_col +  $col_wid($i) ] } ; set total_col [expr $total_col + (($col_len-2) * 2) + 9 ];
    set table_length [llength $table]; set j 0 ; 
    foreach line $table {
      set line1 ""; set line2 "";
      for {set i 0} {$i < $col_len} { incr i } {
        if { $i == 0 } {
          append line1 " | [format "%-$col_wid($i)s" [lindex $line $i]] " 
        } elseif { $i == [expr $col_len -1] } {
          append line1 " | [format "%-$col_wid($i)s" [lindex $line $i]] |" 
        } else  {
          append line1 "| [format "%-$col_wid($i)s" [lindex $line $i]] "
        }
      }

      if { $j == 0 } {
        puts " [string repeat = [expr [string length $line1]-1]]"; 
        puts "$line1";
        #puts " [string repeat = [expr [string length $line1]-1]]"; 
      } elseif { $j == 1 && $j == [expr $table_length - 1] } {
        puts "$line1" ;puts " [string repeat = [expr [string length $line1]-1]]"
      } elseif { $j == [expr $table_length - 1] } {
        puts "$line1" ; puts " [string repeat = [expr [string length $line1]-1]]";
      } else { puts "$line1" }
       incr j;
    }
}
proc print_table{table}{
设置列[L长度[lindex$表0]]
对于{set i 0}{$i<$colu len}{incr i}{set colu wid($i)0}
每行$table{
对于{set i 0}{$i<$colu len}{incr i}{
设置临时列宽度($i)[字符串长度[lindex$行$i];
如果{$colu-wid($i)>$temp-colu-width($i)}{set-colu-wid($i)$colu-wid($i)}其他{set-colu-wid($i)$temp-colu-width($i)}
}
}
集合总列0;对于{set i 0}{$i<$col_len}{incr i}{set total_col[expr$total_col+$col_wid($i)]};集合总列[expr$total_col+($col_len-2)*2)+9];
设置表格长度[L长度$table];设置j 0;
每行$table{
将第1行设置为“”;将第2行设置为“”;
对于{set i 0}{$i<$colu len}{incr i}{
如果{$i==0}{
追加第1行“|[格式“%-$col_wid($i)s”[lindex$行$i]]”
}elseif{$i==[expr$colu len-1]}{
追加第1行“|[格式“%-$col_wid($i)s”[lindex$行$i]]”
}否则{
追加第1行“|[格式“%-$col_wid($i)s”[lindex$行$i]]”
}
}
如果{$j==0}{
放入“[string repeat=[expr[string length$line1]-1]”;
放入“$line1”;
#放入“[string repeat=[expr[string length$line1]-1]”;
}elseif{$j==1&&$j==[expr$table_length-1]}{
放置“$line1”;放置“[string repeat=[expr[string length$line1]-1]”
}elseif{$j==[expr$table_length-1]}{
放置“$line1”;放置“[string repeat=[expr[string length$line1]-1]”;
}else{puts“$line1”}
增量j;
}
}

谢谢@DonalFellows。不确定我是否完全理解了该解决方案,但该解决方案似乎没有产生预期的输出。我只是把输出看作是abc 1 defg 2 hijlk 3 lmn 4我有很多这样的过程(比如abc示例),所以将put更改为通道输出会很乏味,所以我想使用它们生成的任何输出到格式化表中。无论您提出什么解决方案,都必须对代码进行更改。利用编辑的全局搜索“n”替换来减少繁琐的工作。@TradeCoder我写的例子令人困惑,因为我对你的问题有点误读。更新…接近所需,需要一些最终改进。。发布评论是新的,因此无法在评论中发布代码,但添加为新答案以获取详细信息
proc print_table {script} {
    # set up interception
    uplevel 1 $script
    # remove interception
}
> print_table  [capture {abc $list1}]                    
 ========
 | abc   
 | 1     
 | defg  
 | 2     
 | hijlk 
 | 3     
 | lmn   
 | 4     
 ========
proc print_table { table } {
    set col_len [llength [lindex $table 0]]
    for {set i 0} {$i < $col_len} { incr i } { set col_wid($i) 0 }
    foreach line $table {
        for {set i 0} {$i < $col_len} { incr i } { 
            set temp_col_width($i) [string length [lindex $line $i]];
            if { $col_wid($i) > $temp_col_width($i) } { set col_wid($i) $col_wid($i) } else { set col_wid($i) $temp_col_width($i) }
        }
    }
    set total_col 0; for {set i 0} {$i < $col_len} { incr i } { set total_col [expr $total_col +  $col_wid($i) ] } ; set total_col [expr $total_col + (($col_len-2) * 2) + 9 ];
    set table_length [llength $table]; set j 0 ; 
    foreach line $table {
      set line1 ""; set line2 "";
      for {set i 0} {$i < $col_len} { incr i } {
        if { $i == 0 } {
          append line1 " | [format "%-$col_wid($i)s" [lindex $line $i]] " 
        } elseif { $i == [expr $col_len -1] } {
          append line1 " | [format "%-$col_wid($i)s" [lindex $line $i]] |" 
        } else  {
          append line1 "| [format "%-$col_wid($i)s" [lindex $line $i]] "
        }
      }

      if { $j == 0 } {
        puts " [string repeat = [expr [string length $line1]-1]]"; 
        puts "$line1";
        #puts " [string repeat = [expr [string length $line1]-1]]"; 
      } elseif { $j == 1 && $j == [expr $table_length - 1] } {
        puts "$line1" ;puts " [string repeat = [expr [string length $line1]-1]]"
      } elseif { $j == [expr $table_length - 1] } {
        puts "$line1" ; puts " [string repeat = [expr [string length $line1]-1]]";
      } else { puts "$line1" }
       incr j;
    }
}