如何搜索字符串中只有一个可变位置的字符串?

How to search for string with one variable position in the string?

我想在一个大文件中找到所有行,其中包含一个字符串并允许我的字符串中的一个字符不同并且仍然认为它是匹配的。

例如我有这个文件:

>1 agctcaTATAAGtataagctagaagta
>2 gatgctagcgaagtaatgc
>3 atatagcgctagagccgtagta
>4 gctagcaTATCAGgatgtagtagta
...

和这个字符串:tataag,所以我得到这个输出:

>1 agctcaTATAAGtataagctagaagta
>4 gctagcaTATCAGgatgtagtagta

因为第 1 行直接匹配,而第 4 行是除字母 A 之外的所有匹配项,其中它有一个 C

$ # generate the different combinations
$ # assumes search term doesn't have regex metacharacters
$ echo 'tataag' | awk 'BEGIN{FS=OFS=""} {orig=[=10=]; for(i=1;i<=NF;i++)
                       { $i = "."; ORS=(i==NF)?"\n":"|"; print; [=10=]=orig }}'
.ataag|t.taag|ta.aag|tat.ag|tata.g|tataa.

$ # pass it to grep as the regex to be used
$ echo 'tataag' | awk 'BEGIN{FS=OFS=""} {orig=[=10=]; for(i=1;i<=NF;i++)
                       { $i = "."; ORS=(i==NF)?"\n":"|"; print; [=10=]=orig }}' | grep -iEf - ip.txt
>1 agctcaTATAAGtataagctagaagta
>4 gctagcaTATCAGgatgtagtagta

您还可以使用 [acgt] 代替 .

使其更严格
$ echo 'tataag' | awk 'BEGIN{FS=OFS=""} {orig=[=11=]; for(i=1;i<=NF;i++)
                       { $i = "[acgt]"; ORS=(i==NF)?"\n":"|"; print; [=11=]=orig }}'
[acgt]ataag|t[acgt]taag|ta[acgt]aag|tat[acgt]ag|tata[acgt]g|tataa[acgt]

允许一个字符不同:

$ cat tst.awk
BEGIN {
    lgth = length(str)
    for (i=1; i<=lgth; i++) {
        head = esc(substr(str,1,i-1))
        tail = esc(substr(str,i+1))
        part = head "." tail
        reg  = (i>1 ? reg "|" : "") part
    }
    reg = "(" tolower(reg) ")"
    printf "Searching for string \"%s\"\n", str | "cat>&2"
    printf "Searching for regexp \"%s\"\n", reg | "cat>&2"
}
tolower([=10=]) ~ reg

function esc(str) {
    gsub(/[^^\]/,"[&]",str)
    gsub(/\^|\/,"\\&",str)
    return str
}

.

$ awk -v str='tataag' -f tst.awk file
>1 agctcaTATAAGtataagctagaagta
>4 gctagcaTATCAGgatgtagtagta
Searching for string "tataag"
Searching for regexp "(.[a][t][a][a][g]|[t].[t][a][a][g]|[t][a].[a][a][g]|[t][a][t].[a][g]|[t][a][t][a].[g]|[t][a][t][a][a].)"

允许少一个字符:

$ cat tst.awk
BEGIN {
    lgth = length(str)
    for (i=1; i<=lgth; i++) {
        head = esc(substr(str,1,i))
        tail = esc(substr(str,i+1))
        part = head "?" tail
        reg  = (i>1 ? reg "|" : "") part
    }
    reg = "(" tolower(reg) ")"
    printf "Searching for string \"%s\"\n", str | "cat>&2"
    printf "Searching for regexp \"%s\"\n", reg | "cat>&2"
}
tolower([=12=]) ~ reg

function esc(str) {
    gsub(/[^^\]/,"[&]",str)
    gsub(/\^|\/,"\\&",str)
    return str
}

.

$ awk -v str='tataag' -f tst.awk file
>1 agctcaTATAAGtataagctagaagta
>3 atatagcgctagagccgtagta
Searching for string "tataag"
Searching for regexp "([t]?[a][t][a][a][g]|[t][a]?[t][a][a][g]|[t][a][t]?[a][a][g]|[t][a][t][a]?[a][g]|[t][a][t][a][a]?[g]|[t][a][t][a][a][g]?)"

以上所有转义都是为了确保您的字符串被视为文字字符串,即使 if/when 它包含正则表达式元字符。

您可以在完成测试后删除 2 个打印语句。