我有两个文件:
file1
包含唯一单词的列表file2
包含几个句子
我想输出一个制表符分隔的文件,其中列出了每个单词的出现file1
次数file2
同时保留它们在文件 1 中列出的顺序。
例如:
file 1
:dog apple cat
file 2
:the dog played with the cat and the cat was white. the boy ate the apple.
- 期望的输出:
dog 1 apple 1 cat 2
我尝试过现有的答案在社区中,但他们都对输出进行排序。
答案1
在每个 Unix 机器上的任何 shell 中使用任何 POSIX awk:
$ cat tst.awk
BEGIN { OFS="\t" }
NR==FNR {
words[NR] = $1
next
}
{
$0 = " " $0 " "
gsub(/[^[:alpha:]]+/," ")
for ( i in words ) {
word = words[i]
cnts[word] += gsub(" "word" ","&")
}
}
END {
for ( i=1; i in words; i++ ) {
word = words[i]
print word, cnts[word]+0
}
}
$ awk -f tst.awk file1 file2
dog 1
apple 1
cat 2
上面假设“word”都是字母字符,并且您希望匹配区分大小写,或者输入全部为小写,如您的示例中所示,并且 file1 中的单词是唯一的,如您的示例中所示。
答案2
使用乐(以前称为 Perl_6)
以下是一种通用解决方案,用于将一个文件(另存为@a
数组)的行与第二个文件(另存为@b
数组)的行进行匹配,并计算出现次数(即Bag
ging):
raku -e 'my @a = dir(test => "alphabet.txt").IO.lines.reverse; my @b = $*ARGFILES.lines; \
for @a -> $a {@b.grep(/<$a>/).Bag.pairs.say};' alphabet.txt alphabet.txt
在构造 时@a
,Raku 被赋予一个dir()
位置和一个test => "…"
文件名。在构造 时,在命令行中输入一个或多个文件,并通过 Raku 的动态变量@b
读取。$*ARGFILES
通用输入是alphabet.txt
,每行一个字母,读入 Raku 后立即反转,将数组按“z”..“a”顺序排列;
通用输出alphabet.txt
(当在命令行中输入两个“a”..“z”副本时):
(z => 2)
(y => 2)
(x => 2)
(w => 2)
(v => 2)
(u => 2)
(t => 2)
(s => 2)
(r => 2)
(q => 2)
(p => 2)
(o => 2)
(n => 2)
(m => 2)
(l => 2)
(k => 2)
(j => 2)
(i => 2)
(h => 2)
(g => 2)
(f => 2)
(e => 2)
(d => 2)
(c => 2)
(b => 2)
(a => 2)
请注意返回如何保持与数组相同的顺序@a
,以及 Raku 如何不需要调用sort
来生成上面的输出。
最后,解决OP的问题,上面的代码需要更改的就是使用my @b = $*ARGFILES.lines.words
而不是my @b = $*ARGFILES.lines
.
[要获得制表符分隔的输出,请使用.put
而不是.say
在上面的代码中使用。这会删除周围的括号和=>
两列之间的箭头]。
最终代码:
~$ raku -e 'my @a = dir(test => "dog_apple_cat.txt").IO.lines.grep(*.chars); \
my @b = $*ARGFILES.lines.words; for @a -> $a { \
@b.grep(/<$a>/).Bag.pairs.put};' text.txt
dog 1
apple. 1
cat 2