模式匹配并用if-else循环替换字符串

2024-10-01 04:57:40 发布

您现在位置:Python中文网/ 问答频道 /正文

我有一个包含多行的文件,以“1ECLI H---12.345….”开头。我想去掉I和H之间的一个空格,并在H模式的迭代中添加R/S/T。例如,H810如果连续三行重复,则应加上字母R、S(第二次迭代)、T(第三次迭代)。如果是H810R,我们将不胜感激。
文本如下所示

1ECLI  H813   98   7.529   8.326   9.267
1ECLI  H813   99   7.427   8.470   9.251
1ECLI  C814  100   7.621   8.513   9.263
1ECLI  H814  101   7.607   8.617   9.289
1ECLI  H814  102   7.633   8.489   9.156
1ECLI  H814  103   7.721   8.509   9.305
1ECLI   C74  104   8.164   8.733  10.740
1ECLI  H74R  105   8.247   8.690  10.799

一经改变

1ECLI H813R   98   7.529   8.326   9.267
1ECLI H813S   99   7.427   8.470   9.251
1ECLI  C814  100   7.621   8.513   9.263
1ECLI H814R  101   7.607   8.617   9.289
1ECLI H814s  102   7.633   8.489   9.156
1ECLI H814T  103   7.721   8.509   9.305
1ECLI   C74  104   8.164   8.733  10.740
1ECLI  H74R  105   8.247   8.690  10.799

谢谢。你知道吗


Tags: 文件文本字母模式空格h814rh74rh813r
3条回答

下面的代码假定lines是表示文件中某行的字符串列表。你知道吗


with open('filename') as f:
    lines = f.readlines()

from collections import defaultdict
cntd = defaultdict(lambda: 0)
suffix = ['R', 'S', 'T']
newlines = []
for line in lines:
    try:
        kwd = line.split()[1]
    except IndexError:
        newlines.append(line)
        continue
    if kwd[0] == 'H' and kwd[-1].isdigit():
        sfx = suffix[cntd[kwd]]
        idx = line.index(kwd)
        nl = line[:idx -1] + kwd + sfx + line[idx + len(kwd):]
        # nl = line[:idx + len(kwd)] + sfx + line[idx + len(kwd):] # adjust formatting to your taste
        newlines.append(nl)
        cntd[kwd] += 1
    else:
        newlines.append(line)

with open('filename', 'w') as f:
    f.writelines(newlines)

如果您的实际输入文件与您发布的内容相同,那么即使在下面也可以给出所需的输出。你知道吗

awk 'BEGIN{split("R,S,T",a,/,/)}f=$2~/^H[0-9]+$/{$2 = $2 a[++c]}!f{c=0}1' infile 

解释

  • split("R,S,T",a,/,/)-用分隔符逗号分割字符串"R,S,T",并保存在数组a,因此它变成a[1] = R, a[2] = S, a[3] = T

  • f=$2~/^H[0-9]+$/-f是变量,请验证regexp$2 ~ /^H[0-9]+$/,它返回布尔状态。如果它返回true,那么变量f将为真,否则false

  • $2 = $2 a[++c]如果上面的一个为真,那么修改第二个字段,这样第二个字段将有现有值加上数组a值,对应于索引(c),++c是预增量变量

  • !f{c=0}如果变量f为false,则重置变量c,而不是连续的。

  • 1在末尾执行默认操作,即print current/record/row,print $0。要了解awk的工作原理,请尝试awk '1' infile,它将打印所有记录/行,而awk '0' infile不打印任何内容。除零以外的任何数字都是,这将触发默认行为。

测试结果:

$ cat infile
1ECLI  H813   98   7.529   8.326   9.267
1ECLI  H813   99   7.427   8.470   9.251
1ECLI  C814  100   7.621   8.513   9.263
1ECLI  H814  101   7.607   8.617   9.289
1ECLI  H814  102   7.633   8.489   9.156
1ECLI  H814  103   7.721   8.509   9.305
1ECLI   C74  104   8.164   8.733  10.740
1ECLI  H74R  105   8.247   8.690  10.799

$ awk 'BEGIN{split("R,S,T",a,/,/)}f=$2~/^H[0-9]+$/{$2 = $2 a[++c]}!f{c=0}1' infile
1ECLI H813R 98 7.529 8.326 9.267
1ECLI H813S 99 7.427 8.470 9.251
1ECLI  C814  100   7.621   8.513   9.263
1ECLI H814R 101 7.607 8.617 9.289
1ECLI H814S 102 7.633 8.489 9.156
1ECLI H814T 103 7.721 8.509 9.305
1ECLI   C74  104   8.164   8.733  10.740
1ECLI  H74R  105   8.247   8.690  10.799

如果您想要更好的格式,比如tab或其他字符作为字段分隔符,那么您可以使用下面的一个,modify OFS变量

$ awk -v OFS="\t" 'BEGIN{split("R,S,T",a,/,/)}f=$2~/^H[0-9]+$/{$2 = $2 a[++c]}!f{c=0}{$1=$1}1'  infile
1ECLI   H813R   98  7.529   8.326   9.267
1ECLI   H813S   99  7.427   8.470   9.251
1ECLI   C814    100 7.621   8.513   9.263
1ECLI   H814R   101 7.607   8.617   9.289
1ECLI   H814S   102 7.633   8.489   9.156
1ECLI   H814T   103 7.721   8.509   9.305
1ECLI   C74     104 8.164   8.733   10.740
1ECLI   H74R    105 8.247   8.690   10.799

如果您的输入文件与所示示例相同,请尝试以下操作awk,并让我知道这是否对您有帮助。你知道吗

awk '
BEGIN{
  val[1]="R";
  val[2]="S";
  val[3]="T"
}
$2 !~ /^H[0-9]+/ || i==3{
  i=""
}
$2 ~ /^H[0-9]+$/ && /^1ECLI/{
  $2=$2val[++i]
}
1
'   Input_file  > temp_file  && mv  temp_file   Input_file

对答案也作如下解释。你知道吗

awk '
BEGIN{                        ##Starting BEGIN section of awk here.
  val[1]="R";                 ##creating an array named val whose index is 1 and value is string R.
  val[2]="S";                 ##creating array val 2nd element here whose value is S.
  val[3]="T"                  ##creating array val 3rd element here whose value is T.
}
$2 !~ /^H[0-9]+/ || i==3{     ##Checking condition if 2nd field does not start from H and digits after that OR variable i value is equal to 3.
  i=""                        ##Then nullifying the value of variable i here.
}
$2 ~ /^H[0-9]+$/ && /^1ECLI/{ ##Checking here if 2nd field value is starts from H till all digits till end AND line starts from 1ECLI string then do following.
  $2=$2val[++i]               ##re-creating value of 2nd field by adding value of array val whose index is increasing value of variable i.
}
1                             ##Mentioning 1 here, which means it will print the current line.
' Input_file   > temp_file  && mv  temp_file   Input_file                 ##Mentioning Input_file name here.

相关问题 更多 >