按 python 或 Tcl 增加字符串中的数字

Increasing numbers in strings by python or Tcl

我有一些整数字符串(一个字符串中有 2 到 5 个数字,用空格分隔)这是一个例子:

    1    4    5   19
    1    5
    2    3    6   59
    2    6
    3    2    4   60
    3    4
    4    1    3   61
    4    3
   25   13   23   64   65
   13   18
   14   13   15   75
   14   15
   15   14   16   76
   15   14
   45   44  102  103  104

我需要将所有数字重复增加 129,所以开头将是:

130  133  134 148
130  134
131  132  135 188  ...

下一次增加将是:

259  262  263 277
259  263
260  261  264 317 ...

这种字符串分析的最佳选择是什么? 首先统计数字,然后用“0”填充矩阵:[0, 0, 0, 0, 0] 比填写它 - 它将是: 第一行 [1, 4, 5, 19, 0] 第二行 [1, 5, 0, 0, 0]

并增加所有非零的数字。 我正在考虑朝着正确的方向解决这个任务,还是有更简单的方法? 或者有任何现成的解决方案,我只是不明白如何准确地搜索它?

结果必须具有特定格式 - it is PDB file CONECT records

您正在寻找一个二维数组(这是一个矩阵)。

首先,你可以用0来初始化它:

Matrix = [[0 for x in range(20)] for x in range(5)]

您必须根据需要更改号码。 20是行数,5是列数。

之后,你可以把数字放在你想要的地方,使用这个:

Matrix[r][c] = 1

同样,R 是行,C 是列。

如果你想在开始时填充矩阵,你也可以去:

Matrix = [ [1, 4, 5, 19, 0], [1, 5, 0, 0, 0], [0, 0, 0, 0, 0],
[0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0] ]

然后在彼此内部使用两个 for 循环来增加数字

for i in range(20):
   for j in range(5):
      Matrix[i][j] = Matrix[i][j] + 129

如果您知道最终维度,则可以预先分配一个由零组成的 numpy 数组。说出您最初希望如何处理每一行 (process_row),然后对文件中的每一行执行此操作 (process_file)。

import numpy as np

def process_row(row, row_num, out):
    row = row.split()
    nvals = len(row)
    out[row_num,:nvals] = row

def process_file(fname, shape):
    data = np.zeros(shape)
    with open(fname) as fin:
        for i, row in enumerate(fin):
            process_row(row, i, data)
    return data

data = process_file(fname="C:/temp/temp.txt", shape=(15,5))
data[data != 0] += 129

一个Tcl,如果你只需要加起来的数字:

set text {    1    4    5   19
    1    5
    2    3    6   59
    2    6
    3    2    4   60
    3    4
    4    1    3   61
    4    3
   25   13   23   64   65
   13   18
   14   13   15   75
   14   15
   15   14   16   76
   15   14
   45   44  102  103  104}

proc addevery {txt amount} {
    # Creating an alias so we can modify the variable from outside the proc
    upvar text gtext
    set result [list]
    # Split to get lines
    foreach line [split $txt \n] {
        set lineresult [list]
        # Get each number added
        foreach item [regexp -all -inline {\S+} $line] {
            lappend lineresult [expr {$item+$amount}]
        }
        lappend result $lineresult
    }
    set gtext [join $result \n]
    puts $gtext
    return
}

puts "Adding 129:"
addevery $text 129

puts "\nAdding again 129:"
addevery $text 129

ideone demo


编辑:了解潜在问题后;我们必须保持格式(更具体地说,在每一行数字系列之前添加 CONECT,使数字保持 5 space 右缩进格式,并能够输出不同的 'steps'添加到同一文件中的原始数字。最后一件事,第一次迭代实际上不应该向原始数字添加任何内容。

set fin [open "Input.txt" r]
set fout [open "Output.txt" w]

set lines [split [read $fin] "\n"]

# Amount to be added each time
set amount 129
# Number of times to be added
set times 100

proc addevery {amount} {
  global lines
  # Result list
  set lresult [list]
  foreach line $lines {
    # Result line
    set result {}
    # Get every 5 chars of the line
    foreach item [regexp -all -inline {.{5}} $line] {
      # Add, format then append to result line
      append result [format %5s [expr {[string trim $item]+$amount}]]
    }
    # Add line to the result list
    lappend lresult $result
  }
  # Set the lines to the new lines
  set lines $lresult
  return $lresult
}

for {set i 0} {$i < $times} {incr i} {
  # If 0, put the original with CONECT
  if {$i == 0} {
    puts $fout [join [lmap x $lines {set x "CONECT$x"}] "\n"]
  } else {
    puts $fout [join [lmap x [addevery $amount] {set x "CONECT$x"}] "\n"]
  }
}

close $fin
close $fout

作为奖励,python 相当于:

amount = 129
times = 100

import re

def addevery(amount):
  global lines
  lresult = []
  for line in lines:
    result = ''

    for item in re.findall(r'.{5}', line):
      result += "%5s" % (int(item.strip()) + amount)

    lresult.append(result)

  lines = list(lresult)
  return lresult

with open('Input.txt', 'r') as fin:
  with open('Output.txt', 'w') as fout:
    lines = fin.read().split('\n')
    for i in range(0,times):
      if i == 0:
        fout.write('\n'.join(['CONECT'+i for i in lines]) + '\n')
      else:
        fout.write('\n'.join(['CONECT'+i for i in addevery(amount)]) + '\n')

一些 Tcl 解决方案。假设带有数字的原始文本在变量str中,见下文。

一种方法是用命令调用替换所有数字来进行计算,然后对字符串执行替换(格式会有点偏离,因为数字现在会更宽,但空格保持不变):

set res [subst [regsub -all {\d+} $str {[expr {&+129}]}]]

另一种方法是将字符串拆分为行和数字的矩阵并遍历它:

set res {}
foreach line [split $str \n] {
    foreach n $line {
        append res [format %5s [incr n 129]]
    }
    append res \n
}

使用 Tcl 8.6 lmap 映射命令的相同方法:

set res [join [lmap line [split $str \n] {
    join [lmap n $line {
        format %5s [incr n 129]
    }] {}
}] \n]

在这两种情况下,结果字符串将在变量 res 中,并保留原始格式。

ETA:右对齐输出:

set res [join [lmap line [split $str \n] {
    format %25s [join [lmap n $line {
        format %5s [incr n 129]
    }] {}]
}] \n]

变量 str 是这样分配的,作为纯文本(换行符在末尾被修剪以避免空的幽灵元素):

set str [string trim {
    1    4    5   19
    1    5
    2    3    6   59
    2    6
    3    2    4   60
    3    4
    4    1    3   61
    4    3
   25   13   23   64   65
   13   18
   14   13   15   75
   14   15
   15   14   16   76
   15   14
   45   44  102  103  104
} \n]

文档:append, expr, foreach, format, incr, lmap, regsub, set, split, string, subst

Tcl:lmap

需要 Tcl 8.6
package require Tcl 8.6

# list of strings
set strings {
    {    1    4    5   19}
    {    1    5}
    {    2    3    6   59}
    {    2    6}
    {    3    2    4   60}
    {    3    4}
    {    4    1    3   61}
    {    4    3}
    {   25   13   23   64   65}
    {   13   18}
    {   14   13   15   75}
    {   14   15}
    {   15   14   16   76}
    {   15   14}
    {   45   44  102  103  104}
}

proc incr_all {listvar {n 1}} {
    upvar 1 $listvar lst
    set lst [lmap sublist $lst {lmap elem $sublist {expr {$elem + $n}}}]
}

proc format_strings {lst} {
    join [lmap sublist $lst {format [string repeat {%5s} [llength $sublist]] {*}$sublist}] \n
}

incr_all strings 119
puts [format_strings $strings]

输出

  120  123  124  138
  120  124
  121  122  125  178
  121  125
  122  121  123  179
  122  123
  123  120  122  180
  123  122
  144  132  142  183  184
  132  137
  133  132  134  194
  133  134
  134  133  135  195
  134  133
  164  163  221  222  223
set incriment 127
set molecules 450
set fout [open "Results.txt" w]
close $fout

proc addevery {filein fileout amount times} {
  set fh [open $filein r]
  set fout [open $fileout a+]
  while {[gets $fh line] != -1} {
    set result {}
    foreach item [regexp -all -inline {.{5}} $line] {
      append result [format %5s [expr {[string trim $item]+($amount*$times)}]]
    }
    puts $fout "CONECT$result"
  }
  close $fh
  close $fout
}

for {set i 0} {$i < $molecules} {incr i} {
    addevery "Connections_.txt" "Results.txt" $incriment $i
}

感谢 https://whosebug.com/users/1578604/jerry 它正在运行,但尚未优化。