【问题标题】:How to match for multiple patterns in the specific column?如何匹配特定列中的多个模式?
【发布时间】:2015-09-10 13:25:41
【问题描述】:

我想知道是否有更有效的方法来使用 awk/grep/sed 来解决以下问题?

我想解析我的输入文件的某个列(在本示例中为第 1 列)并使用 awk/grep/任何其他函数来子集和选择与我的查询匹配的模式。例如给出下面的文件;

chr1    3009844 3009908 DXX 42  -
chr2    3000386 3000450 DXX 15  -
chr3    3000386 3000450 DXX 15  -
chr4    3000386 3000450 DXX 15  -
chr5    3000386 3000450 DXX 15  -
chr6    3000386 3000450 DXX 15  -
chr7    3000386 3000450 DXX 15  -
chr8    3000386 3000450 DXX 15  -
chr9    3000386 3000450 DXX 15  -
chr10   3000386 3000450 DXX 15  -
chr11   3000386 3000450 DXX 15  -
chr12   3000386 3000450 DXX 15  -
chr13   3000386 3000450 DXX 15  -
chr14   3000386 3000450 DXX 15  -
chr15   3000386 3000450 DXX 15  -
chr16   3000386 3000450 DXX 15  -
chr17   3000386 3000450 DXX 15  -
chr18   3000386 3000450 DXX 15  -
chr19   3000386 3000450 DXX 15  -
chrX    3000386 3000450 DXX 15  -
chrY    3000386 3000450 DXX 15  -
chr1_GL456210_random    3000386 3000450 DXX 15  -
chr1_GL456211_random    3000386 3000450 DXX 15  -
chr1_GL456212_random    3000386 3000450 DXX 15  -
chr1_GL456221_random    3000386 3000450 DXX 15  -
chr4_GL456216_random    3000386 3000450 DXX 15  -
chr4_JH584292_random    3000386 3000450 DXX 15  -
chr4_JH584295_random    3000386 3000450 DXX 15  -
chr5_GL456354_random    3000386 3000450 DXX 15  -
chr5_JH584296_random    3000386 3000450 DXX 15  -
chr5_JH584297_random    3000386 3000450 DXX 15  -
chr5_JH584299_random    3000386 3000450 DXX 15  -
chrX_GL456233_random    3000386 3000450 DXX 15  -

我只想有一个输出,例如,第一列中只有 chr1-chr22、chrX 和 chrY;

chr1    3009844 3009908 DXX 42  -
chr2    3000386 3000450 DXX 15  -
chr3    3000386 3000450 DXX 15  -
chr4    3000386 3000450 DXX 15  -
chr5    3000386 3000450 DXX 15  -
chr6    3000386 3000450 DXX 15  -
chr7    3000386 3000450 DXX 15  -
chr8    3000386 3000450 DXX 15  -
chr9    3000386 3000450 DXX 15  -
chr10   3000386 3000450 DXX 15  -
chr11   3000386 3000450 DXX 15  -
chr12   3000386 3000450 DXX 15  -
chr13   3000386 3000450 DXX 15  -
chr14   3000386 3000450 DXX 15  -
chr15   3000386 3000450 DXX 15  -
chr16   3000386 3000450 DXX 15  -
chr17   3000386 3000450 DXX 15  -
chr18   3000386 3000450 DXX 15  -
chr19   3000386 3000450 DXX 15  -
chrX    3000386 3000450 DXX 15  -
chrY    3000386 3000450 DXX 15  -

我设法使用以下命令找到了解决方案:

awk '$1 == "chr1" || $1 == "chr2" || $1 == "chr3" || $1 == "chr4" || $1 == "chr5" || $1 == "chr6" || $1 == "chr7" || $1 == "chr8" || $1 == "chr9" || $1 == "chr10" || $1 == "chr11" || $1 == "chr12" || $1 == "chr13" || $1 == "chr14" || $1 == "chr15" || $1 == "chr16" || $1 == "chr17" || $1 == "chr18" || $1 == "chr19" || $1 == "chr20" || $1 == "chrX" || $1 == "chrY"'  in_file > out_file

它工作正常,但想知道亲爱的会员是否有更优雅的方式来解决问题?或者,如果您可以指出资源以在 linux 中探索 awk/grep,我们将不胜感激!

【问题讨论】:

    标签: bash unix awk grep pattern-matching


    【解决方案1】:

    您可以将此简化的正则表达式与grep 一起使用:

    grep "^chr\(1\?[0-9]\|2[012]\|[XY]\)[[:space:]]" filename
    

    逻辑包含在括号内\(..\)

    • 1\?[0-9] - 匹配 0-9 可选地以 1 开头
    • 2[012] - 匹配 2 后跟 0、1 或 2
    • [XY] - 匹配 X 或 Y

    【讨论】:

    • 非常感谢 :) 太优雅了!! :) 冰中是否有一个地方指定我们只搜索第一列?你是一个天才! :)
    • @Learner 正则表达式中的锚^ 意味着我们将始终从行的开始开始匹配,但它并不是真正的“列”感知。使用 awk 的 $1 的另一个答案将在第一个字段上运行,默认情况下是空格分隔
    【解决方案2】:

    使用正则表达式:

    awk '$1 ~ /^chr(1?[0-9]|2[0-2]|X|Y)$/' file
    

    这使用$1 ~ /^pattern$/ 选择恰好包含pattern 的好行(注意^ 用于开始,$ 用于结束)。

    该模式采用chr(..|..|..) 形式,意思是:匹配chr 后跟| 中的任一() 中的分隔条件。

    这些条件可以是:

    • 一个数字(可能是 1 后跟一个数字)(1?[0-9])
    • 数字为 2 + 0、1、2 中的任何一个 (2[0-2])
    • X

    Demo自动讲解:https://regex101.com/r/gH1kS4/2

    【讨论】:

    • 这也将匹配chr0。如果这不是故意的,我们可以稍微重构一下。
    • @BlueMoon 真的!没有检查完整的解释,而只是示例输入/所需的输出。已更新,谢谢。
    • 非常酷!如果我理解代码 $1- 特定于第一列。 “~”?? “~”的作用是什么? .我不知道什么是“1”?正在做..你介意详细说明一下吗? :)
    • @Learner 是的,field ~ /pattern/ 是对字段内容执行正则表达式的方式。 1? 是一个正则表达式,意思是:1 可以出现一次,也可以不出现,所以它是可选的。请参阅我的更新答案。
    • 知道了,我会阅读更多关于正则表达式和 awk 的内容。非常感谢您的解释!
    【解决方案3】:

    如果您想要一些更容易维护的东西(例如编辑或添加新的线条/模式以匹配)并且还想要一些更容易理解的东西,特别是如果您刚刚开始使用正则表达式,请使用 grep -f match.list input.txt 格式:

    使用您要匹配的模式创建一个文件 (match.list):

    ^chr[1-9][[:space:]]\|      # this matches chr1-chr9
    ^chr1[0-9][[:space:]]\|     # this matches chr10-chr19
    ^chr2[12][[:space:]]\|      # this matches chr21-22
    ^chr[XY][[:space:]]\|       # this matches chrX and chrY
    new_string_or_pattern\|     # ... your new pattern ...
    

    然后像这样调用grep

    grep -f match.list input.txt
    

    正如您在上面看到的,您甚至可以使用 \| 技巧将 cmets 添加到模式列表中(每个模式以 \| 结尾),这样您就可以记住昨天做了什么或在哪里找到了正则表达式。您可以通过添加新行来添加新的固定字符串或模式。此外,如果您发现创建复杂的正则表达式很困难,您可以只创建一个包含您想要匹配的固定字符串的模式文件:

    ^chrX
    ^chrY
    ...
    

    这种方法的另一个好处是您可以维护多个模式文件,代表您可能需要每天运行的不同子查询。例如

    grep -f chromosomes_n input.txt
    grep -f chromosomes_xy input.txt
    grep -f chromosomes_random input.txt
    

    该方法的唯一缺点是,如果您在每个文件中添加十几个模式,grep 会变慢。但只有当您的输入文件有数十万行时,这才会成为问题。

    【讨论】:

      【解决方案4】:

      鉴于您发布的示例,您需要获得所需的输出是以下任一(或其他简单的 RE):

      awk '$1 !~ /_/' file
      awk '$1 ~ /^[[:alnum:]]+$/' file
      

      因此,根据您的实际需求,您可能根本不必列出特定的“模式”。

      【讨论】:

        【解决方案5】:

        下面会做的工作。

        grep -v -w 'random'
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2016-04-24
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多