it-swarm.cn

如何计算每行中特定字符的数量?

我想知道如何通过某些文本处理实用程序计算每行中特定字符的数量?

例如,在以下文本的每一行中计算"

"hello!" 
Thank you!

第一行有两个,第二行有0。

另一个示例是在每一行中计数(

97
Tim

您可以使用sedawk来做到这一点:

_$ sed 's/[^"]//g' dat | awk '{ print length }'
2
0
_

其中dat是您的示例文本,sed删除(对于每行)所有非_"_个字符,并且awk为每一行打印其大小(即length为等效于length($0),其中_$0_表示当前行)。

对于另一个字符,您只需要更改sed表达式即可。例如对于_(_可以:

_'s/[^(]//g'
_

更新:sed对于任务来说有点过头了-tr就足够了。 tr的等效解决方案是:

_$ tr -d -c '"\n' < dat | awk '{ print length; }'
_

表示tr删除字符集_-c_中不是(_"\n_表示补码)的所有字符。

115
maxschlepzig

我只会用awk

awk -F\" '{print NF-1}' <fileName>

在这里,我们将字段分隔符(带有-F标志)设置为字符",那么我们要做的就是打印字段数NF-1。目标字符的出现次数比分隔的字段数少一。

对于由Shell解释的有趣字符,您只需要确保将其转义即可,否则命令行将尝试对它们进行解释。所以对于"),您需要对字段分隔符(使用\)。

52
Martin York

使用tr ard wc

function countchar()
{
    while IFS= read -r i; do printf "%s" "$i" | tr -dc "$1" | wc -m; done
}

用法:

$ countchar '"' <file.txt  #returns one count per line of file.txt
1
3
0

$ countchar ')'           #will count parenthesis from stdin
$ countchar '0123456789'  #will count numbers from stdin
15
Stéphane Gimenez

bashzshyashksh的某些实现/版本的另一种不依赖外部程序的实现:

while IFS= read -r line; do 
  line="${line//[!\"]/}"
  echo "${#line}"
done <input-file

采用 line="${line//[!(]}"用于计数(

11
enzotib

如果匹配数太大(使用我的情况),使用awk的答案将失败。对于 loki-astari 的答案,报告以下错误:

awk -F" '{print NF-1}' foo.txt 
awk: program limit exceeded: maximum number of fields size=32767
    FILENAME="foo.txt" FNR=1 NR=1

对于 enzotib 的答案(以及 manatwork 的答案),出现分段错误:

awk '{ gsub("[^\"]", ""); print length }' foo.txt
Segmentation fault

maxschlepzigsed解决方案可以正常工作,但速度较慢(下面的时序)。

这里还没有建议一些解决方案。首先,使用grep

grep -o \" foo.txt | wc -w

并使用Perl

Perl -ne '$x+=s/\"//g; END {print "$x\n"}' foo.txt

以下是一些解决方案的时间安排(从最慢到最快顺序排列);我把事情限制在这里。 'foo.txt'是一个包含一行和一个长字符串的文件,其中包含84922个匹配项。

## sed solution by [maxschlepzig]
$ time sed 's/[^"]//g' foo.txt | awk '{ print length }'
84922
real    0m1.207s
user    0m1.192s
sys     0m0.008s

## using grep
$ time grep -o \" foo.txt | wc -w
84922
real    0m0.109s
user    0m0.100s
sys     0m0.012s

## using Perl
$ time Perl -ne '$x+=s/\"//g; END {print "$x\n"}' foo.txt
84922
real    0m0.034s
user    0m0.028s
sys     0m0.004s

## the winner: updated tr solution by [maxschlepzig]
$ time tr -d -c '\"\n' < foo.txt |  awk '{ print length }'
84922
real    0m0.016s
user    0m0.012s
sys     0m0.004s
10
josephwb

另一个awk解决方案:

awk '{print gsub(/"/, "")}'
9
Stéphane Chazelas

使用awk和gsub的另一种可能的实现:

_awk '{ gsub("[^\"]", ""); print length }' input-file
_

函数gsub与sed的_'s///g'_等效。

使用gsub("[^(]", "")计数_(_。

8
enzotib

我决定写一个C程序,因为我很无聊。

您可能应该添加输入验证,但是除此之外。

#include <stdio.h>
#include <string.h>

int main(int argc, char *argv[])
{
        char c = argv[1][0];
        char * line = NULL;
        size_t len = 0;
        while (getline(&line, &len, stdin) != -1)
        {
                int count = 0;
                char * s = line;
                while (*s) if(*s++ == c) count++;
                printf("%d\n",count);
        }
        if(line) free(line);
}
6
user606723

对于字符串,最简单的方法是trwc(无需使用awksed过度杀伤)-但请注意上述有关tr的注释,计数字节,而不是字符-

echo $x | tr -d -c '"' | wc -m

其中$x是包含要评估的字符串(不是文件)的变量。

6
Ocumo

这是另一个只需要STD C和更少内存的C解决方案:

#include <stdio.h>

int main(int argc, char **argv)
{
  if (argc < 2 || !*argv[1]) {
    puts("Argument missing.");
    return 1;
  }
  char c = *argv[1], x = 0;
  size_t count = 0;
  while ((x = getc(stdin)) != EOF)
    if (x == '\n') {
      printf("%zd\n", count);
      count = 0;
    } else if (x == c)
      ++count;
  return 0;
}
4
maxschlepzig

也许更直接,纯粹的答案是使用split。 Split接受一个字符串并将其转换为数组,返回值是生成的数组项的数量+1。

以下代码将打印出“出现在每行上的次数”。

awk ' {print (split($0,a,"\"")-1) }' file_to_parse

有关拆分的更多信息 http://www.staff.science.uu.nl/~oostr102/docs/nawk/nawk_92.html

3
bleurp

我们可以将grepregex结合使用,使其更加简单和强大。

计算特定字符。

$ grep -o '"' file.txt|wc -l

计算包括空格字符在内的特殊字符。

$ grep -Po '[\W_]' file.txt|wc -l

在这里,我们选择带有[\S\s]的任何字符,并通过-o选项,使grep在单独的行中打印每个匹配项(即每个字符)。然后使用wc -l对每一行进行计数。

3
Kannan Mohan

对于纯bash解决方案(但是,它是bash特定的):如果$x是包含您的字符串的变量:

x2="${x//[^\"]/}"
echo ${#x2}

${x//除去"以外的所有字符,_${#x2}计算其余字符的长度。

(使用expr的原始建议存在问题,请参见注释:)

expr length "${x//[^\"]/}"
2
Marian

这是一个简单的Python脚本,用于查找"在文件的每一行中:

#!/usr/bin/env python2
with open('file.txt') as f:
    for line in f:
        print line.count('"')

在这里,我们使用了内置count类型的str方法。

2
heemayl

a替换为要计算的字符。输出是每行的计数器。

Perl -nE 'say y!a!!'
2
JJoao

提出的解决方案的时间比较(不是答案)

答案的效率并不重要。但是,按照@josephwb方法,我尝试安排所有给出的答案的时间。

我将维克多·雨果(Victor Hugo)的《悲惨世界》(Les Miserables)(很棒的书!)的葡萄牙语翻译作为输入,并计算“ a”的出现。我的版有5卷,很多页...

$ wc miseraveis.txt 
29331  304166 1852674 miseraveis.txt 

C答案是使用gcc编译的(无优化)。

每个答案运行3次,然后选择最佳答案。

不要太相信这些数字(我的机器正在执行其他任务,等等)。我与您分享这些时间,因为我得到了一些意想不到的结果,并且我相信您还会发现更多...

  • 16个定时解决方案中的14个花费不到1秒的时间;比0.1s少9个,其中许多使用管道
  • 2个解决方案,逐行使用bash,通过创建新流程来处理30k行,并在10s/20s内计算出正确的解决方案。
  • grep -oP agrep -o a(10; 11 vs 12)
  • C和其他语言之间的差异并不像我预期的那么大。 (7; 8 vs 2; 3)
  • (欢迎结论)

(结果以随机顺序)

=========================1 maxschlepzig
$ time sed 's/[^a]//g' mis.txt | awk '{print length}' > a2
real    0m0.704s ; user 0m0.716s
=========================2 maxschlepzig
$ time tr -d -c 'a\n' < mis.txt | awk '{ print length; }' > a12
real    0m0.022s ; user 0m0.028s
=========================3 jjoao
$ time Perl -nE 'say y!a!!' mis.txt  > a1
real    0m0.032s ; user 0m0.028s
=========================4 Stéphane Gimenez
$ function countchar(){while read -r i; do echo "$i"|tr -dc "$1"|wc -c; done }

$ time countchar "a"  < mis.txt > a3
real    0m27.990s ; user    0m3.132s
=========================5 Loki Astari
$ time awk -Fa '{print NF-1}' mis.txt > a4
real    0m0.064s ; user 0m0.060s
Error : several -1
=========================6 enzotib
$ time awk '{ gsub("[^a]", ""); print length }' mis.txt > a5
real    0m0.781s ; user 0m0.780s
=========================7 user606723
#include <stdio.h> #include <string.h> // int main(int argc, char *argv[]) ...  if(line) free(line); }

$ time a.out a < mis.txt > a6
real    0m0.024s ; user 0m0.020s
=========================8 maxschlepzig
#include <stdio.h> // int main(int argc, char **argv){if (argc < 2 || !*argv[1]) { ...  return 0; }

$ time a.out a < mis.txt > a7
real    0m0.028s ; user 0m0.024s
=========================9 Stéphane Chazelas
$ time awk '{print gsub(/a/, "")}'< mis.txt > a8
real    0m0.053s ; user 0m0.048s
=========================10 josephwb count total
$ time grep -o a < mis.txt | wc -w > a9
real    0m0.131s ; user 0m0.148s
=========================11 Kannan Mohan count total
$ time grep -o 'a' mis.txt | wc -l > a15
real    0m0.128s ; user 0m0.124s
=========================12 Kannan Mohan count total
$ time grep -oP 'a' mis.txt | wc -l > a16
real    0m0.047s ; user 0m0.044s
=========================13 josephwb Count total
$ time Perl -ne '$x+=s/a//g; END {print "$x\n"}'< mis.txt > a10
real    0m0.051s ; user 0m0.048s
=========================14 heemayl
#!/usr/bin/env python2 // with open('mis.txt') as f: for line in f: print line.count('"')

$ time pyt > a11
real    0m0.052s ; user 0m0.052s
=========================15 enzotib
$ time  while IFS= read -r line; do   line="${line//[!a]/}"; echo "${#line}"; done < mis.txt  > a13
real    0m9.254s ; user 0m8.724s
=========================16 bleurp
$ time awk ' {print (split($0,a,"a")-1) }' mis.txt > a14
real    0m0.148s ; user 0m0.144s
Error several -1
2
JJoao
grep -n -o \" file | sort -n | uniq -c | cut -d : -f 1

grep可以完成所有繁重的工作:报告在每个行号找到的每个字符。剩下的只是对每行的计数求和,并格式化输出。

去除 -n并获得整个文件的计数。

在0.015秒内计算1.5Meg文本文件的速度似乎很快。
并且可以处理字符(不是字节)。

1
user79743

Bash的解决方案。没有调用任何外部程序(对于短字符串更快)。

如果值在变量中:

$ a='"Hello!"'

这会打印出多少" 它包含了:

$ b="${a//[^\"]}"; echo "${#b}"
2
1
Isaac