返回文本行中多个字符串匹配的多个位置
Returning multiple positions of multiple string matches within lines of text
我有一个文本文件,例如:
>HiC_scaffold_1 LN:i:45809557 RC:i:152227 XC:f:0.987707
CAGGAAAGCCGCGTAAGTGAATATATGCAGCAACCTACCGAAAAGTGGGCCAATCCAACCAATCTTGCTTGCACAATGGAAAGAGCCACTGGTTTATCTCTCCATCGAATCAAATTAGCCAAAGGTGTGCGTTCATGAGCCCATGCTAAAGTTTCAATCAATTCTTGCCAATATCCACGCCAGGAAATTAAGAACATAAATCCAGTGCTGCAGC
>HiC_scaffold_2 LN:i:32008785 RC:i:102679 XC:f:0.981906
AAAGCTGCCCCTAGGCCGAACAAAATGGTCGGATGCGAAGAGAAATTGTTTGGCTCAAAATTTTACGAGCTTGTGCAGAACTTCAAGGCAATCATATCGGCAGGTGACACGAAGTGATTCGAGTTCGGCAGCTTTGCCCCTCCTTTTTCCTTGACGAAAGATAACTTTTTCTGAAAATAACACGTGCCCCGATTCCGGCCGAAATGACTCGAAT
>HiC_scaffold_3 LN:i:26569524 RC:i:79397 XC:f:0.996709
CCTAAACCCTAAACCCTAAACCCCTAAACCCTAAACCCTAACCCTAAACCCTAAACCCCTAAACCCTAAACCCTAAACCCTAAACCCTAAACCCTAAACCCTAAACCCTAAACCCTAAACCCTAAAACCCACCTAAACCCTAAACCCTAAACCCCCTAAACCCAAAACGCTGCCCCTAAACCCTAAACCCTAAACCCGCAGCTAACCCTAAACC
我想在不以“>”开头的行中找到模式“GCAGC”或“GCTGC”出现的位置。
有没有办法使用 sed
或 awk
来 return 匹配的行号,以及每行中匹配的索引(即,数字每行中每个匹配项开始的字符数)?
谢谢!
假设您的数据在文件 data.txt
中,简单的解决方案是:
awk 'BEGIN {RS="\n>";} \
{ for (j=1;j<=length($i)-4;j++) { \
if (substr($i,j,5) == "GCAGC") { \
print "entry " NR " column " j ": GCAGC" \
} else if(substr($i,j,5) == "GCTGC") { \
print "entry " NR " column " j ": GCTGC" \
} \
} \
}' data.txt
这里我假设您的条目由“\n>”分隔并打印条目编号,因为我假设这就是您想要的。否则你可以省略第一部分并简单地 运行
awk '{ for (j=1;j<=length($i)-4;j++) { \
if (substr($i,j,5) == "GCAGC") { \
print "line " NR " column " j ": GCAGC" \
} else if(substr($i,j,5) == "GCTGC") { \
print "line " NR " column " j ": GCTGC" \
} \
} \
}' data.txt
这给了你行号。有关详细信息,请参阅 documentation.
这是一个处理重叠模式的解决方案:
BEGIN {
patternRegex = "GCAGC|GCTGC"
}
/^[^>]/ {
offset = 0
target = [=10=]
match(target, patternRegex)
while (RSTART > 0) {
matchedString = substr(target, RSTART, RLENGTH)
printf "line %d: %s at position %d\n", NR, matchedString, offset + RSTART
offset += RSTART + length("CG*") - 1
target = substr(target, RSTART + length("CG*"))
match(target, patternRegex)
}
}
如果脚本存储在 find-patterns.awk
中,输入在 input.txt
中,我们得到以下输出:
$ awk -f find-patterns.awk < input.txt
line 2: GCAGC at position 27
line 2: GCTGC at position 207
line 2: GCAGC at position 210
line 4: GCTGC at position 4
line 4: GCAGC at position 128
line 6: GCTGC at position 169
line 6: GCAGC at position 198
假设如果可能出现重叠的目标字符串,您想了解所有这些,这将在每个 Unix 机器上的任何 shell 中使用任何 awk 工作:
$ cat tst.awk
!/^>/ {
while ( match([=10=],/GC[AT]GC/) ) {
print NR, RSTART, substr([=10=],RSTART,RLENGTH)
[=10=] = substr([=10=],1,RSTART-1) " " substr([=10=],RSTART+1)
}
}
$ awk -f tst.awk file
2 27 GCAGC
2 207 GCTGC
2 210 GCAGC
4 4 GCTGC
4 128 GCAGC
6 169 GCTGC
6 198 GCAGC
7 4 GCAGC
7 7 GCAGC
7 10 GCAGC
以上是此输入文件的 运行:
$ cat file
>HiC_scaffold_1 LN:i:45809557 RC:i:152227 XC:f:0.987707
CAGGAAAGCCGCGTAAGTGAATATATGCAGCAACCTACCGAAAAGTGGGCCAATCCAACCAATCTTGCTTGCACAATGGAAAGAGCCACTGGTTTATCTCTCCATCGAATCAAATTAGCCAAAGGTGTGCGTTCATGAGCCCATGCTAAAGTTTCAATCAATTCTTGCCAATATCCACGCCAGGAAATTAAGAACATAAATCCAGTGCTGCAGC
>HiC_scaffold_2 LN:i:32008785 RC:i:102679 XC:f:0.981906
AAAGCTGCCCCTAGGCCGAACAAAATGGTCGGATGCGAAGAGAAATTGTTTGGCTCAAAATTTTACGAGCTTGTGCAGAACTTCAAGGCAATCATATCGGCAGGTGACACGAAGTGATTCGAGTTCGGCAGCTTTGCCCCTCCTTTTTCCTTGACGAAAGATAACTTTTTCTGAAAATAACACGTGCCCCGATTCCGGCCGAAATGACTCGAAT
>HiC_scaffold_3 LN:i:26569524 RC:i:79397 XC:f:0.996709
CCTAAACCCTAAACCCTAAACCCCTAAACCCTAAACCCTAACCCTAAACCCTAAACCCCTAAACCCTAAACCCTAAACCCTAAACCCTAAACCCTAAACCCTAAACCCTAAACCCTAAACCCTAAAACCCACCTAAACCCTAAACCCTAAACCCCCTAAACCCAAAACGCTGCCCCTAAACCCTAAACCCTAAACCCGCAGCTAACCCTAAACC
fooGCAGCAGCAGCbar
与perl
(不重叠):
$ perl -lne 'if(!/^>/){print join " ", $., $-[0]+1, $& while /GCAGC|GCTGC/g}' ip.txt
2 27 GCAGC
2 207 GCTGC
4 4 GCTGC
4 128 GCAGC
6 169 GCTGC
6 198 GCAGC
if(!/^>/)
行不以 >
开头
$.
给出行号
$-[0]
给出了匹配的起始位置(从0开始的索引,所以添加了1
)
$&
有匹配的部分
join " "
使用 space 作为分隔符来组合所需的值
while /GCAGC|GCTGC/g
遍历给定正则表达式的所有匹配项
要同时匹配重叠的情况,请将正则表达式更改为 /(?=(GCAGC|GCTGC))/g
,以便要匹配的字符串现在位于先行捕获组中。这将尝试在不消耗字符的情况下在每个位置进行匹配,并且匹配的部分将从 </code> 中获得。如果搜索词本身重叠(例如:<code>ABC
和 ABCD
),则交替中最左边的词优先。
$ perl -lne 'if(!/^>/){print join " ", $., $-[0]+1, while /(?=(GCAGC|GCTGC))/g}' ip.txt
2 27 GCAGC
2 207 GCTGC
2 210 GCAGC
4 4 GCTGC
4 128 GCAGC
6 169 GCTGC
6 198 GCAGC
使用 ripgrep,这可能比其他解决方案更快。但缺点是这不会过滤掉以 >
开头的行,并且仅适用于非重叠情况:
$ rg --vimgrep -o --no-filename 'GCAGC|GCTGC' ip.txt
2:27:GCAGC
2:207:GCTGC
4:4:GCTGC
4:128:GCAGC
6:169:GCTGC
6:198:GCAGC
--vimgrep
专为与 vim
一起使用而设计,它给出行号和列号
-o
只得到匹配的部分而不是整行
--no-filename
避免输出中的文件名前缀
- 如果你想要 space 分隔符而不是
:
字符,请使用 --field-match-separator=' '
这可能对你有用(GNU sed 和 ripgrep):
sed '/>/g' file | rg --column -o 'GC[AT]GC'| sed 'y/:/ /'
包含 >
的空行,使用 ripgrep 完成大部分工作并使用最终的 sed 调用清理结果。
选择:
rg --column -o '>|GC[AT]GC' file | sed -E 'y/:/ /;/>/h;G;/^(\S* ).*\n/!P;d'
感谢 Sundeep。
我有一个文本文件,例如:
>HiC_scaffold_1 LN:i:45809557 RC:i:152227 XC:f:0.987707
CAGGAAAGCCGCGTAAGTGAATATATGCAGCAACCTACCGAAAAGTGGGCCAATCCAACCAATCTTGCTTGCACAATGGAAAGAGCCACTGGTTTATCTCTCCATCGAATCAAATTAGCCAAAGGTGTGCGTTCATGAGCCCATGCTAAAGTTTCAATCAATTCTTGCCAATATCCACGCCAGGAAATTAAGAACATAAATCCAGTGCTGCAGC
>HiC_scaffold_2 LN:i:32008785 RC:i:102679 XC:f:0.981906
AAAGCTGCCCCTAGGCCGAACAAAATGGTCGGATGCGAAGAGAAATTGTTTGGCTCAAAATTTTACGAGCTTGTGCAGAACTTCAAGGCAATCATATCGGCAGGTGACACGAAGTGATTCGAGTTCGGCAGCTTTGCCCCTCCTTTTTCCTTGACGAAAGATAACTTTTTCTGAAAATAACACGTGCCCCGATTCCGGCCGAAATGACTCGAAT
>HiC_scaffold_3 LN:i:26569524 RC:i:79397 XC:f:0.996709
CCTAAACCCTAAACCCTAAACCCCTAAACCCTAAACCCTAACCCTAAACCCTAAACCCCTAAACCCTAAACCCTAAACCCTAAACCCTAAACCCTAAACCCTAAACCCTAAACCCTAAACCCTAAAACCCACCTAAACCCTAAACCCTAAACCCCCTAAACCCAAAACGCTGCCCCTAAACCCTAAACCCTAAACCCGCAGCTAACCCTAAACC
我想在不以“>”开头的行中找到模式“GCAGC”或“GCTGC”出现的位置。
有没有办法使用 sed
或 awk
来 return 匹配的行号,以及每行中匹配的索引(即,数字每行中每个匹配项开始的字符数)?
谢谢!
假设您的数据在文件 data.txt
中,简单的解决方案是:
awk 'BEGIN {RS="\n>";} \
{ for (j=1;j<=length($i)-4;j++) { \
if (substr($i,j,5) == "GCAGC") { \
print "entry " NR " column " j ": GCAGC" \
} else if(substr($i,j,5) == "GCTGC") { \
print "entry " NR " column " j ": GCTGC" \
} \
} \
}' data.txt
这里我假设您的条目由“\n>”分隔并打印条目编号,因为我假设这就是您想要的。否则你可以省略第一部分并简单地 运行
awk '{ for (j=1;j<=length($i)-4;j++) { \
if (substr($i,j,5) == "GCAGC") { \
print "line " NR " column " j ": GCAGC" \
} else if(substr($i,j,5) == "GCTGC") { \
print "line " NR " column " j ": GCTGC" \
} \
} \
}' data.txt
这给了你行号。有关详细信息,请参阅 documentation.
这是一个处理重叠模式的解决方案:
BEGIN {
patternRegex = "GCAGC|GCTGC"
}
/^[^>]/ {
offset = 0
target = [=10=]
match(target, patternRegex)
while (RSTART > 0) {
matchedString = substr(target, RSTART, RLENGTH)
printf "line %d: %s at position %d\n", NR, matchedString, offset + RSTART
offset += RSTART + length("CG*") - 1
target = substr(target, RSTART + length("CG*"))
match(target, patternRegex)
}
}
如果脚本存储在 find-patterns.awk
中,输入在 input.txt
中,我们得到以下输出:
$ awk -f find-patterns.awk < input.txt
line 2: GCAGC at position 27
line 2: GCTGC at position 207
line 2: GCAGC at position 210
line 4: GCTGC at position 4
line 4: GCAGC at position 128
line 6: GCTGC at position 169
line 6: GCAGC at position 198
假设如果可能出现重叠的目标字符串,您想了解所有这些,这将在每个 Unix 机器上的任何 shell 中使用任何 awk 工作:
$ cat tst.awk
!/^>/ {
while ( match([=10=],/GC[AT]GC/) ) {
print NR, RSTART, substr([=10=],RSTART,RLENGTH)
[=10=] = substr([=10=],1,RSTART-1) " " substr([=10=],RSTART+1)
}
}
$ awk -f tst.awk file
2 27 GCAGC
2 207 GCTGC
2 210 GCAGC
4 4 GCTGC
4 128 GCAGC
6 169 GCTGC
6 198 GCAGC
7 4 GCAGC
7 7 GCAGC
7 10 GCAGC
以上是此输入文件的 运行:
$ cat file
>HiC_scaffold_1 LN:i:45809557 RC:i:152227 XC:f:0.987707
CAGGAAAGCCGCGTAAGTGAATATATGCAGCAACCTACCGAAAAGTGGGCCAATCCAACCAATCTTGCTTGCACAATGGAAAGAGCCACTGGTTTATCTCTCCATCGAATCAAATTAGCCAAAGGTGTGCGTTCATGAGCCCATGCTAAAGTTTCAATCAATTCTTGCCAATATCCACGCCAGGAAATTAAGAACATAAATCCAGTGCTGCAGC
>HiC_scaffold_2 LN:i:32008785 RC:i:102679 XC:f:0.981906
AAAGCTGCCCCTAGGCCGAACAAAATGGTCGGATGCGAAGAGAAATTGTTTGGCTCAAAATTTTACGAGCTTGTGCAGAACTTCAAGGCAATCATATCGGCAGGTGACACGAAGTGATTCGAGTTCGGCAGCTTTGCCCCTCCTTTTTCCTTGACGAAAGATAACTTTTTCTGAAAATAACACGTGCCCCGATTCCGGCCGAAATGACTCGAAT
>HiC_scaffold_3 LN:i:26569524 RC:i:79397 XC:f:0.996709
CCTAAACCCTAAACCCTAAACCCCTAAACCCTAAACCCTAACCCTAAACCCTAAACCCCTAAACCCTAAACCCTAAACCCTAAACCCTAAACCCTAAACCCTAAACCCTAAACCCTAAACCCTAAAACCCACCTAAACCCTAAACCCTAAACCCCCTAAACCCAAAACGCTGCCCCTAAACCCTAAACCCTAAACCCGCAGCTAACCCTAAACC
fooGCAGCAGCAGCbar
与perl
(不重叠):
$ perl -lne 'if(!/^>/){print join " ", $., $-[0]+1, $& while /GCAGC|GCTGC/g}' ip.txt
2 27 GCAGC
2 207 GCTGC
4 4 GCTGC
4 128 GCAGC
6 169 GCTGC
6 198 GCAGC
if(!/^>/)
行不以>
开头
$.
给出行号$-[0]
给出了匹配的起始位置(从0开始的索引,所以添加了1
)$&
有匹配的部分join " "
使用 space 作为分隔符来组合所需的值while /GCAGC|GCTGC/g
遍历给定正则表达式的所有匹配项
要同时匹配重叠的情况,请将正则表达式更改为 /(?=(GCAGC|GCTGC))/g
,以便要匹配的字符串现在位于先行捕获组中。这将尝试在不消耗字符的情况下在每个位置进行匹配,并且匹配的部分将从 </code> 中获得。如果搜索词本身重叠(例如:<code>ABC
和 ABCD
),则交替中最左边的词优先。
$ perl -lne 'if(!/^>/){print join " ", $., $-[0]+1, while /(?=(GCAGC|GCTGC))/g}' ip.txt
2 27 GCAGC
2 207 GCTGC
2 210 GCAGC
4 4 GCTGC
4 128 GCAGC
6 169 GCTGC
6 198 GCAGC
使用 ripgrep,这可能比其他解决方案更快。但缺点是这不会过滤掉以 >
开头的行,并且仅适用于非重叠情况:
$ rg --vimgrep -o --no-filename 'GCAGC|GCTGC' ip.txt
2:27:GCAGC
2:207:GCTGC
4:4:GCTGC
4:128:GCAGC
6:169:GCTGC
6:198:GCAGC
--vimgrep
专为与vim
一起使用而设计,它给出行号和列号-o
只得到匹配的部分而不是整行--no-filename
避免输出中的文件名前缀- 如果你想要 space 分隔符而不是
:
字符,请使用--field-match-separator=' '
这可能对你有用(GNU sed 和 ripgrep):
sed '/>/g' file | rg --column -o 'GC[AT]GC'| sed 'y/:/ /'
包含 >
的空行,使用 ripgrep 完成大部分工作并使用最终的 sed 调用清理结果。
选择:
rg --column -o '>|GC[AT]GC' file | sed -E 'y/:/ /;/>/h;G;/^(\S* ).*\n/!P;d'
感谢 Sundeep。