按 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
编辑:了解潜在问题后;我们必须保持格式(更具体地说,在每一行数字系列之前添加 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
它正在运行,但尚未优化。
我有一些整数字符串(一个字符串中有 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
编辑:了解潜在问题后;我们必须保持格式(更具体地说,在每一行数字系列之前添加 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
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 它正在运行,但尚未优化。