Answers:
您可以使用sed
和进行操作awk
:
$ sed 's/[^"]//g' dat | awk '{ print length }'
2
0
dat
sed在示例文本的哪里,sed删除(对于每一行)所有非"
字符,并awk
为每一行打印其大小(即length
等于length($0)
,其中$0
表示当前行)。
对于另一个字符,您只需要更改sed表达式即可。例如用于(
:
's/[^(]//g'
更新: sed
对于任务来说有点过头了- tr
足够。的等效解决方案tr
是:
$ tr -d -c '"\n' < dat | awk '{ print length; }'
意味着tr
删除所有不在-c
字符集中的字符(表示补码)"\n
。
tr
&wc
版本更有效。
ß
(utf hex:c3 9f)(而不是"
)进行的快速测试可以按预期工作,即tr
,sed
并且awk
可以毫无问题地进行补码/替换/计数。
tr
,包括GNU tr和经典Unix tr,都使用单字节字符,并且不兼容Unicode。.引自Wikipedia tr(Unix) ..尝试以下代码段:echo "aā⧾c" | tr "ā⧾" b
...在Ubuntu 10.04上... ß
是单字节扩展拉丁字符和被处理tr
......真正的问题在这里不是tr
不处理Unicode(因为所有字符都是Unicode),这是真的那么tr
一次只能处理一个字节..
我只会用awk
awk -F\" '{print NF-1}' <fileName>
在这里,我们将字段分隔符(带有-F标志)设置为字符,"
然后我们要做的就是打印字段数NF
-1。目标字符的出现次数将比分隔的字段数少一。
对于由Shell解释的有趣字符,您只需要确保将其转义即可,否则命令行将尝试对它们进行解释。因此,对于这两者"
,)
您都需要转义字段分隔符(带有\
)。
'
)。此外,它具有空行的奇怪行为。
"
因此我认为必须使代码能够使用它。这取决于您所使用的外壳天气,角色需要逃脱,但bash / tcsh都需要逃脱“
-F'"'
。
awk -F"$1" '{print NF==0?NF:NF-1}' filename
使用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
$IFS
,否则read
将从头到尾修剪它们。
tr
实现支持多字节字符,但是wc -c
对字节计数,而不是字符计数(需要wc -m
字符)。
然而,这不依赖于外部程序,在另一个实施bash
,zsh
,yash
和一些实现/版本ksh
:
while IFS= read -r line; do
line="${line//[!\"]/}"
echo "${#line}"
done <input-file
使用line="${line//[!(]}"
计数(
。
eof=false; IFS=; until $eof; do read -r || eof=true; echo "$REPLY"; done
/
bash不需要的尾随。这是ksh的要求吗?
/
在较旧的ksh版本中需要尾随,在较旧的bash版本中也需要IIRC。
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
maxschlepzig的sed
解决方案可以正常工作,但速度较慢(下面的时序)。
这里还没有建议一些解决方案。首先,使用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
另一个awk
解决方案:
awk '{print gsub(/"/, "")}'
使用awk和gsub的另一种可能的实现:
awk '{ gsub("[^\"]", ""); print length }' input-file
该功能gsub
等效于sed的's///g'
。
使用gsub("[^(]", "")
计数(
。
awk '{print gsub(/"/,"")}' input-file
这样就足够了,因为“对于每个与字符串t中的正则表达式r匹配的子字符串,替换字符串s,并返回替换数目。” (man awk)
我决定写一个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);
}
free(line)
因为退出程序会隐式释放所有分配的内存-然后有一个return 0;
...;)的位置。即使在示例中,将返回码保持未定义也不是好方法。顺便说一句,getline
是GNU扩展-如果有人想知道的话。
f
从其他代码中多次调用,那么您必须在该函数末尾free
的最后一次调用之后调用。getline
f
这是另一个只需要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;
}
\n
不是真实行。这与我的其他sed / awk(tr / awk)答案相同。
我们可以使用grep
with regex
使其更简单和强大。
计算特定字符。
$ grep -o '"' file.txt|wc -l
计算包括空格字符在内的特殊字符。
$ grep -Po '[\W_]' file.txt|wc -l
在这里,我们选择带有[\S\s]
和的任何字符,并带有-o
选项grep
以在单独的行中打印每个匹配项(即每个字符)。然后wc -l
用来计数每一行。
"
每行有多少个;以及其他任何字符。看到他的问题,也接受了答案。
也许更直接,纯粹的答案是使用split。Split接受一个字符串并将其转换为数组,返回值为生成的数组项的数量+1。
以下代码将打印出“出现在每行上的次数”。
awk ' {print (split($0,a,"\"")-1) }' file_to_parse
有关拆分的更多信息http://www.staff.science.uu.nl/~oostr102/docs/nawk/nawk_92.html
对于纯bash解决方案(但是,它是bash特定的):If $x
是包含您的字符串的变量:
x2="${x//[^\"]/}"
echo ${#x2}
的${x//
事情,除了删除所有字符"
,${#x2}
计算该休息的长度。
(使用expr
其中的原始建议存在问题,请参阅评论:)
expr length "${x//[^\"]/}"
expr
并计算字节,而不是字符。与其他人expr
:expr "x${x...}" : "x.*" - 1
提出的解决方案的时间比较(不是答案)
答案的效率并不重要。但是,按照@josephwb方法,我尝试安排所有给出的答案的时间。
我将Victor Hugo的《悲惨世界》(伟大的书!)的葡萄牙语翻译作为输入,并计算“ a”的出现。我的版有5卷,很多页...
$ wc miseraveis.txt
29331 304166 1852674 miseraveis.txt
C答案是使用gcc编译的(无优化)。
每个答案运行3次,然后选择最佳答案。
不要太相信这些数字(我的机器正在执行其他任务,等等)。我与您分享这些时间,因为我得到了一些意想不到的结果,并且我相信您还会发现更多...
grep -oP a
树的速度快于grep -o a
(10; 11 vs 12)(结果以随机顺序)
=========================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
grep -n -o \" file | sort -n | uniq -c | cut -d : -f 1
grep可以完成所有繁重的工作:报告在每个行号找到的每个字符。剩下的只是对每行的计数求和,并格式化输出。
删除-n
并获取整个文件的计数。
在0.015秒内计算1.5Meg文本文件的速度似乎很快。
并可以处理字符(不是字节)。