【问题标题】:pattern match and replace the string with if else loop模式匹配并用 if else 循环替换字符串
【发布时间】:2018-04-18 08:24:02
【问题描述】:

我有一个包含多行以“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

谢谢。

【问题讨论】:

  • 为什么H74R 什么也得不到?如果 H 重复超过 3 次会怎样?
  • 它已经有 R... 我想在模式“H digit digit digit”中添加字母(H 为 3 位)。
  • 去掉空格并不难,但如果你能回答 PoGibas 的问题,回答起来会容易得多
  • 是不是总会有H\d\d\d连续出现3次?
  • H 有两个数字和一个字母 R 很好,并且符合所需的命名风格。三位数的 H 缺少 R/S/T 字母。我必须添加它...

标签: python r awk sed


【解决方案1】:

如果您的 Input_file 与显示的示例相同,请尝试关注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.

【讨论】:

  • 它给出错误:awk:1:意外字符''' awk:14:意外字符'''
  • @amruta,不让我知道哪些错误,我帮不了你。请让我知道错误?也是 Solaris/SunOS 系统上的 GUESS,将 awk 更改为 /usr/xpg4/bin/awk 、 /usr/xpg6/bin/awk 或 nawk。
  • 我做了一些小改动,效果不错,但没有添加 R S 和 T 字母
  • 但是更改并没有以某种方式完成......我很抱歉你错过了我的文字的最后一部分。脚本运行但未进行任何更改......
  • 我得到了输出文件,但没有进行任何更改.. 作为 R、S 或 T。
【解决方案2】:

如果您的真实输入文件与您发布的相同,即使低于一个也可以提供所需的输出。

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 是变量,验证正则表达式 $2 ~ /^H[0-9]+$/,它返回布尔状态。如果它返回true,那么变量f 将为真,否则false

  • $2 = $2 a[++c]如果上面一个为真,则修改第二个字段,所以第二个字段将有现有值加上数组a值,对应索引(c),++c是pre-递增变量

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

  • 1 最后执行默认操作,即打印当前/记录/行,print $0。要了解 awk 的工作原理,请尝试 awk '1' infile,它将打印所有记录/行,而 awk '0' infile 不打印任何内容。任何非零的数字都是true,这会触发默认行为。

测试结果:

$ 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 或其他字符作为字段分隔符,那么您可以使用下面的一个,修改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

【讨论】:

  • 谢谢。它工作得很好。只有一个查询..我将如何设置选项卡如下.. 1ECLI C814 100 7.621 8.513 9.263 1ECLI H814R 101 7.607 8.617 9.289 而不是 1ECLI C814 100 7.621 8.513 9.263 1ECLI H814R 1071 9..>8 714R 1071 9..66
  • 使用-v OFS="\t",而{$1=$1} awk 将修改输出字段分隔符
  • 1ECLI C814 100 7.621 8.513 9.263 1ECLI H814R 101 7.607 8.617 9.289代替1ECLI C814 100 7.621 8.513 9.263 1ECLI H814R 101 7.607 8.617 9.289我无法展示由于某种原因导致的领先和滞后的标签图案..
  • 你是怎么尝试的?您可以在评论中发布您的命令,以确保 OFS 正常工作,您可以更改 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' test.in > test.out ,OFS 工作正常,我检查了你建议的方式。
【解决方案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)

【讨论】:

  • 我收到以下错误。文件“./test.py”,第 5 行,在 中的行中:NameError: name 'lines' is not defined 我的文件名是 test.dat,我把代码放在 test.py... 应该我用'test.dat'改变'行'??
  • @amruta 阅读我回答中的第一句话。您应该将文件中的所有行读入lines。您需要这方面的帮助吗?
  • 感谢您的再次解释。但现在它给了我这个错误,文件“./test.py”,第 9 行,在 kwd = line.split()[1] IndexError: list index out of range 这是什么意思?
  • 这意味着您的输入文件中的某些行没有您帖子中显示的结构。例如,您可能有空行。我将修复代码以在一分钟内跳过这些代码。
  • 我没有得到任何输出。输出文件“test.log”为空。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-03-22
  • 2020-07-12
  • 2014-08-31
  • 2019-03-01
  • 2013-10-24
相关资源
最近更新 更多