【问题标题】:How to replace some digits with letters in each line of a file (according to the letter that exist in column 5th and 6th of that line)?如何在文件的每一行中用字母替换一些数字(根据该行第 5 列和第 6 列中存在的字母)?
【发布时间】:2012-02-08 16:34:31
【问题描述】:

我有一个以空格分隔的文件,如下所示:

probeset_id submitted_id chr snp_pos alleleA alleleB 562_201 562_202 562_203 562_204 562_205 562_206 562_207 562_208 562_209 562_210 562_211 562_212 562_213 562_214 562_215 562_216 562_217 562_218 562_219 562_220 562_221 562_222 562_223 562_224 562_225 562_226 562_227 562_228 562_229 562_230 562_231 562_232 562_233 562_234 562_235 562_236 562_237 562_238 562_239 562_240 562_241 562_242 562_243 562_244 562_245 562_246 562_247 562_248 562_249 562_250 562_251 562_252 562_253 562_254 562_255 562_256 562_257 562_258 562_259 562_260 562_261 562_262 562_263 562_264 562_265 562_266 562_267 562_268 562_269 562_270 562_271 562_272 562_273 562_274 562_275 562_276 562_277 562_278 562_279 562_280 562_281 562_283 562_284 562_285 562_289 562_291 562_292 562_294 562_295 562_296 562_400 562_401 562_402 562_403 562_404 562_405 
AX-75448119 Chr1_41908741 1 41908741 T C 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 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 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 1 1 1 1 1 1 0 1 0 0 0 0 2 2 0 0 0 0 0 1 0 0 0 0 0 
AX-75448118 Chr1_41908545 1 41908545 T A 2 2 2 2 2 2 2 2 2 0 0 0 0 0 0 0 0 0 0 0 1 2 2 2 2 2 2 2 2 2 0 0 0 0 0 1 1 0 1 1 0 0 0 0 0 0 1 2 2 2 0 1 1 1 2 -1 1 2 0 0 2 1 1 0 1 0 1 2 1 0 0 1 2 2 1 2 2 0 1 2 2 2 2 2 2 0 1 0 0 0 1 2 2 2 2 0

我想根据第 5 列和第 6 列用字母替换数字

  1. 0 替换为$5 $5(第5 列重复两次)例如,如果第5 列是T,则将0 替换为T T
  2. 2 替换为$6 $6(第6 列重复两次)例如,如果第6 列是C,则将2 替换为C C
  3. 1 替换为$5 $6 例如,如果第5 列和第6 列分别为TC,则将1 替换为T C
  4. -1 替换为? ?

需要注意的是,第 5 列和第 6 列可以是 T、A、C 和 G

所以我想要输出的是:

AX-75448119 Chr1_41908741 1 41908741 T C T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T C T T T T T T T C T C T C T C T C T C T T T C T T T T T T T T C C C C T T T T T T T T T T T C T T T T T T T T T T 
AX-75448118 Chr1_41908545 1 41908545 T A A A A A A A A A A A A A A A A A A A T T T T T T T T T T T T T T T T T T T T T T T A A A A A A A A A A A A A A A A A A A T T T T T T T T T T T A T A T T T A T A T T T T T T T T T T T T T A A A A A A A T T T A T A T A A A ? ? T A A A T T T T A A T A T A T T T A T T T A A A T A T T T T T A A A A A T A A A A A T T T A A A A A A A A A A A A A T T T A T T T T T T T A A A A A A A A A T T

我不知道这是否可以通过 awk 实现!如果不是,我会在 python 中尝试,但我更喜欢像 awk 这样的 Linux 命令(它比 python 快得多,因为我使用的文件有 120 万行,我的计算机可以通过 python 交换!)

【问题讨论】:

  • 请贴出你目前所写的代码。这不是“为 me.com 做我的工作”。你试过什么?
  • 我用'sed'尝试了mayn的东西,但它不起作用!我只是想知道可以使用的命令,然后我可以自己尝试一下!
  • 是什么让你觉得 awk 会比 python 快?
  • 您的样本输出与您的规格不符。第二行的一堆“A”从哪里来的?
  • @mahmood:(1) 请更新问题以回答 cmets。 (2) 请不要在 cmets 中发布代码,请用代码更新问题。

标签: linux awk gsub


【解决方案1】:
NR>1{
  o="1"; z="0"; t="2"
  if($5 == "T" && $6 == "C")
    o="T C"
  if($5 == "T")
    z="T T"
  if($6 == "C")
    t="C C"
  if($6 == "A")
    t="A A"
  for (i=7; i<=NF; i++) {
    gsub(/1/,o,$i)
    gsub(/0/,z,$i)
    gsub(/2/,t,$i)
    gsub(/-1/,"? ?", $i)
  }
}1

输出

$ awk -f allele.awk allele.in
probeset_id submitted_id chr snp_pos alleleA alleleB 562_201 562_202 562_203 562_204 562_205 562_206 562_207 562_208 562_209 562_210 562_211 562_212 562_213 562_214 562_215 562_216 562_217 562_218 562_219 562_220 562_221 562_222 562_223 562_224 562_225 562_226 562_227 562_228 562_229 562_230 562_231 562_232 562_233 562_234 562_235 562_236 562_237 562_238 562_239 562_240 562_241 562_242 562_243 562_244 562_245 562_246 562_247 562_248 562_249 562_250 562_251 562_252 562_253 562_254 562_255 562_256 562_257 562_258 562_259 562_260 562_261 562_262 562_263 562_264 562_265 562_266 562_267 562_268 562_269 562_270 562_271 562_272 562_273 562_274 562_275 562_276 562_277 562_278 562_279 562_280 562_281 562_283 562_284 562_285 562_289 562_291 562_292 562_294 562_295 562_296 562_400 562_401 562_402 562_403 562_404 562_405
AX-75448119 Chr1_41908741 1 41908741 T C T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T C T T T T T T T C T C T C T C T C T C T T T C T T T T T T T T C C C C T T T T T T T T T T T C T T T T T T T T T T
AX-75448118 Chr1_41908545 1 41908545 T A A A A A A A A A A A A A A A A A A A T T T T T T T T T T T T T T T T T T T T T T 1 A A A A A A A A A A A A A A A A A A T T T T T T T T T T 1 1 T T 1 1 T T T T T T T T T T T T 1 A A A A A A T T 1 1 1 A A ? ? 1 A A T T T T A A 1 1 T T 1 T T 1 A A 1 T T T T 1 A A A A 1 A A A A T T 1 A A A A A A A A A A A A T T 1 T T T T T T 1 A A A A A A A A T T

注意:您的规范仍然不完整,当第 5 列和第 6 列分别不是 T C 时,您永远不会说如何处理 1。您忽略了许多排列。

【讨论】:

  • 完美运行我必须做一些修改!唯一的事情是首先你应该运行awk 'NR&gt;1{ for (i=7; i&lt;=NF; i++) {gsub(/-1/,"? ?", $i) }}1' test.txt,因为如果不是,-1 将被转移到 -T 或 -A 和......其他东西。然后运行其余的命令。谢谢
【解决方案2】:

这可能对你有用:

awk 'NR>1{a=$3;$3="@";gsub(/ -1\>/," ? ?");gsub(/\<0\>/,$5 " " $5);gsub(/\<1\>/,$5 " " $6);gsub(/\<2\>/,$6 " " $6);$3=a;print}' file

【讨论】:

    【解决方案3】:

    这也将在前 4 列上进行替换,并且我没有打扰 1 或 -1 的情况(留给读者作为练习),但您应该能够轻松地扩展它以适应: $ perl -lape 's/0/$F[ 4 ] $F[ 4 ]/g; s/2/$F[ 5 ] $F[ 5 ]/g' 输入

    我真的怀疑 awk 在这方面会比 perl 快。

    【讨论】:

      【解决方案4】:

      awk 绝对是你的朋友。

      awk 逐行读取数据文件。您不需要/不想拥有任何类型的循环结构(除非您变得非常先进)。

      awk '{print $0}' inFile
      

      您是否只需要读取文件的每一行并将其打印出来(它会显示在您的屏幕上,所以不要做大文件)

      请注意,我使用$0 表示“整行数据”。

      Awk 还具有引用每个数据字段的变量,您可以使用 $2 之类的值来打印文件中的第二个字段。

      我想根据第 5 列和第 6 列用字母替换数字。所以我想要的是用 T T (如果第 5 列是 T)和 2 用 C C (如果第 6 列是 C)和 1 用 T C (如果第 5 列和第 6 列分别是 T 和 C)替换 0 我想要将 -1 更改为 ? ?或者 ! !

      因此,对于您的问题,您需要测试每一行,测试某些字段并设置新值。

      awk 'NR>1{
        # replace 0 with T T (if the 5th column is T)
        if ($5 == 0) $5="TT"
        # and 2 by C C (if the 6th column is C)
        if ($6 == 2) $6="CC"
        # and 1 with T C (if the 5th and 6th columns are T and C respectively)
        if ($5 == "T" && $6 == "C") $1="1"
      }'  inputFile  | sed 's/TT/T T/; s/CC/C C/'
      

      要更改某个字段之后的所有字段,请根据需要合并此代码,

      awk 'NR>1{
        # replace 0 with T T (if the 5th column is T)
        if ($5 == 0) { 
           for (i=5; i<=NF;i++) {
               printf("T ")
           }
           printf("\n")
       }
       ......
      

      }' 输入文件 ...

      NR&gt;1 表示只处理大于 1 的行号。

      请注意,我们使用简单的逻辑来实现您的测试。添加越来越多很容易。回想一下,很多时候使用“分层”逻辑是有意义的if ($5==0) { ... } else if ($5 == 1) { ....}

      例如,一个问题是您要求输出“C C”。当您在 awk 中执行 `$5="C C" 之类的操作时,awk 将重新校准其字段编号,因此 $5 将是 C 而 $6 将是 C,而不是之前的值。

      我采用了打印“CC”的捷径,然后在最后使用 sed 创建您的规范指示的“CC”值。

      我不知道如何处理

      我想将 -1 更改为 ? ?或者 ! !

      因为它必须是一个或另一个,我不确定您要在哪个字段上进行操作。使用上面的代码作为指导。如果您遇到困难,请发布一个新问题,其中包含示例输入数据、预期输出、当前输出和您正在使用的代码。

      我希望这会有所帮助。

      【讨论】:

      • 我想我的问题问得很糟糕,或者你错过了一些了解我的方式!我想从第 7 列替换到最后!我想根据第 5 列和第 6 列中存在的字母替换它们!所以我想如果它是 0 用 $5 $5 替换(我的意思是第 5 列的两次重复),如果它是 1 用 $5 $6 替换,如果 2 用 $6 $6 和 -1 替换? ?
      • 您可以从我的示例中了解 awk 现在是如何工作的吗?我再补充一点。请参阅添加的示例代码。祝你好运。
      【解决方案5】:

      最好通过相等而不是通过正则表达式检查字段的值:

      awk '
          NR==1 {print; next}
          {check0 = check1 = check2 = 0}
          $5 == "T"              {check0 = 1}
          $5 == "T" && $6 == "C" {check1 = 1}
          $6 == "C" || $6 == "A" {check2 = 1}
          {
              for (idx=7; idx <= NF; idx++)
                  if      (check0 && $idx == 0) $idx = "T T"
                  else if (check1 && $idx == 1) $idx = "T C"
                  else if (check2 && $idx == 2) $idx = $6 " " $6
                  else if ($idx == -1)          $idx = "? ?"
              print
          }
      '
      

      【讨论】:

        猜你喜欢
        • 2020-05-21
        • 1970-01-01
        • 2022-08-23
        • 2015-02-05
        • 2018-05-12
        • 2017-08-10
        • 1970-01-01
        • 2016-02-08
        • 1970-01-01
        相关资源
        最近更新 更多