回答:
sed
andでそれを行うことができますawk
:
$ 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
。
tr
&wc
バージョンよりも効率的です。
ß
(UTF進:C3の9F)(代わりには"
、すなわち、予想通り)作品tr
、sed
およびawk
-のUbuntu 10.04システム上で問題なくカウント/ /交換を補完します。
tr
GNU trおよび古典的なUnix trを含むほとんどのバージョンは、シングルバイト文字で動作し、Unicodeに準拠していません。Wikipediatr(Unix)から引用..このスニペットを試してください:echo "aā⧾c" | tr "ā⧾" b
... Ubuntu 10.04で... ß
はシングルバイトです拡張ラテン文字とによって処理されtr
、ここで...本当の問題はないことがあるtr
ことは、(すべての文字がUnicodeであるため)、それは本当にあるのUnicodeに対応していないtr
だけ一度に一つのバイトを処理します。..
私はちょうどawkを使用します
awk -F\" '{print NF-1}' <fileName>
ここでは、文字であることを(-Fフラグ付きで)フィールドセパレータを設定"
し、我々が行うすべての分野のプリント枚数であるNF
-対象文字の出現の1の数は、区切られたフィールドの数より1つ少なくなります。
シェルによって解釈されるおかしな文字については、エスケープする必要があります。そうしないと、コマンドラインがそれらを解釈しようとします。したがって、両方の場合、フィールド区切り文字をエスケープする必要が"
あり)
ます(で\
)。
'
)。また、空の行で奇妙な動作をします。
"
ので、コードをそれで動作させる義務があります。それはあなたの文字をエスケープする必要がありますが、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の古いバージョンで必要であり、IIRCはbashの古いバージョンでも必要です。
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
sed
溶液maxschlepzigは正常に動作しますが、(以下タイミング)遅いです。
ここではまだ提案されていないソリューションがいくつかあります。まず、次を使用しgrep
ます。
grep -o \" foo.txt | wc -w
そして使用perl
:
perl -ne '$x+=s/\"//g; END {print "$x\n"}' foo.txt
いくつかのソリューションのタイミングを以下に示します(最も遅いものから最も速いものへ)。ここではワンライナーに限定しました。「foo.txt」は、84922件の一致を含む1行と1つの長い文字列を含むファイルです。
## 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と同等です's///g'
。
gsub("[^(]", "")
カウントに使用します(
。
awk '{print gsub(/"/,"")}' input-file
「文字列tの正規表現rに一致する各部分文字列について、文字列sを置換し、置換の数を返します。」(男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
、他のコードから数回呼び出されるスタンドアロン関数-say-になるようにコードをリファクタリングする場合、この関数の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
各行のカウントに使用します。
"
、各行にいくつありますか。その他の文字用。彼の質問と受け入れられた答えを見てください。
たぶんもっと単純な、純粋にawkの答えは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固有です):$x
文字列を含む変数の場合:
x2="${x//[^\"]/}"
echo ${#x2}
${x//
事は除くすべての文字を削除し"
、${#x2}
この残りの長さを計算します。
(expr
どちらに問題があるかについての元の提案、コメントを参照:)
expr length "${x//[^\"]/}"
expr
であり、文字ではなくバイトをカウントすることに注意してください。他とexpr
:expr "x${x...}" : "x.*" - 1
提示されたソリューションの時間比較(答えではありません)
回答の効率は重要ではありません。それでも、@ josephwbのアプローチに従って、提示されたすべての回答の時間を測ろうとしました。
入力として、Victor Hugoのポルトガル語翻訳「Les Miserables」(素晴らしい本です!)を使用し、「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テキストファイルを数えるのは速いようです。
また、文字(バイトではなく)でも機能します。