한 줄에 공백도 없고 다른 줄도 없는 텍스트 데이터가 많이 있습니다. 실제로 흐름은 0.2Gb/s입니다.여기, 그러나 이 작업에서는 발생 횟수를 계산하는 것이 빈 줄을 계산하는 것보다 더 어렵습니다. 게임은
585e0000fe5a1eda480000000d00030007000000cd010000
예제 데이터 하위 집합은 다음과 같습니다.여기라고2015.6.30_data.txt완전한 바이너리 데이터여기라고0002.원시. 경기는 1회 발생했습니다.2015.6.30_data.txt하지만 전체 데이터에서는 10배입니다.0002.원시한 줄에. 를 통해 txt 데이터를 준비했습니다 xxd -ps 0002.raw > /tmp/1 && fold -w2 /tmp/1 > /tmp/2 && gsed ':a;N;$!ba;s/\n//g' /tmp/2 > /tmp/3
. 구현은 빠를수록 좋습니다. 열에 큰 문자열을 준비하려면 이것을 사용할 수 있습니다 xxd -ps 0002.raw > /tmp/1 && fold -w2 /tmp/1 > /tmp/2
. 현재 속도는 게임당 0.0012초입니다. 이는 전체 데이터 파일에서 10게임당 0.012초이므로 느립니다.
Grep은 이 작업을 행별로 수행하므로 셀 수 없습니다. Vim에서는 %s/veryLongThing//gn
작업을 완료하는 것만으로는 충분하지 않습니다. 이 명령은 wc
문자, 바이트, 줄만 제공하므로 적합한 도구는 아니지만 다른 것과 결합하는 것은 가능합니다. 아마도 GNU Find와 Sed의 조합일 것입니다. 하지만 모든 구현이 너무 복잡해 보입니다.
Mikeserv의 답변 결과
$ cat 1.7.2015.sh
time \
( export ggrep="$(printf '^ \376Z\36\332H \r \3 \a \315\1')" \
gtr='\1\3\a\r\36HZ^\315\332\376'
LC_ALL=C
gtr -cs "$gtr" ' [\n*]' |
gcut -sd\ -f1-6 |
ggrep -xFc "$ggrep"
) <0002.raw
$ sh 1.7.2015.sh
1
real 0m0.009s
user 0m0.006s
sys 0m0.007s
-----------
$ cat 1.7.2015.sh
time \
( set x58 x5e x20 x20 xfe x5a x1e xda \
x48 x20 x20 x20 x0d x20 x03 x20 \
x07 x20 x20 x20 xcd x01 x20 x20
export ggrep="$(shift;IFS=\\;printf "\\$*")" \
gtr='\0\1\3\a\r\36HXZ^\315\332\376' \
LC_ALL=C i=0
while [ "$((i+=1))" -lt 1000 ]
do gcat 0002.raw; done |
gtr -cd "$gtr" |gtr 'X\0' '\n ' |
gcut -c-23 |ggrep -xFc "$ggrep"
)
$ sh 1.7.2015.sh
9990
real 0m4.371s
user 0m1.548s
sys 0m2.167s
모든 도구는 GNU coreutils이며 코드에 제공하는 모든 옵션이 있습니다. 그러나 GNU devtools와는 다를 수 있습니다. Mikeserv는 코드를 990번 실행하고 10개의 이벤트를 가지므로 총 9990개의 이벤트가 정확합니다.
슈퍼 문자열의 일치 항목 수를 효율적으로 계산하는 방법은 무엇입니까?
답변1
GNU 구현 grep
(최신 버전은 완전한(대부분 호환) 재작성이지만 대부분의 최신 BSD에도 있음)은 -o
출력 옵션을 지원합니다.모두일치하는 부품.
LC_ALL=C grep -ao CDA | wc -l
그러면 모든 발생 횟수가 계산됩니다.
LC_ALL=C grep -abo CDA
바이트 오프셋으로 찾으십시오.
LC_ALL=C
grep
비용이 많이 드는 UTF-8 구문 분석을 시도하지 않도록 하십시오 (여기서 고정된 ASCII 문자열 검색을 사용하면 grep
자체적으로 UTF-8 구문 분석을 최적화할 수 있어야 하지만). 바이너리에 대해 생각하라고 -a
말하는 것은 또 다른 GNUism입니다 .grep
답변2
그래서 16진수 문자열을 바이트로 인쇄했지만 NUL을 <spaces>로 바꿨습니다.(주로 스키마에서 NUL을 얻는 방법을 모르기 때문입니다 grep
):
time \
( set x58 x5e x20 x20 xfe x5a x1e xda \
x48 x20 x20 x20 x0d x20 x03 x20 \
x07 x20 x20 x20 xcd x01 x20 x20
export grep="$(shift;IFS=\\;printf "\\$*")" \
tr='\0\1\3\a\r\36HXZ^\315\332\376' \
LC_ALL=C i=0
while [ "$((i+=1))" -lt 1000 ]
do cat 0002.raw; done |
tr -cd "$tr" |tr 'X\0' '\n ' |
cut -c-23 |grep -xFc "$grep"
)
거기에 있는 변수는 16진수 문자열의 바이트 값에 대한 8진수 이스케이프/ASCII 문자로 구성됩니다. 왜냐하면 그 보수를 제거 tr
하고 싶기 때문입니다 . 그런 다음 일치시키려고 시도할 수 있는 가장 긴 줄이 가 있는 바이트 인지 확인 하고 X 문자를 ewline으로 변환하는 동시에 NUL을 <spaces>로 대체하여 문자열이 항상 줄의 제목이 되도록 했습니다 .tr
-d
grep
-c-23
cut
tr
\n
cat
여기서는 파이프라인에서 원본 바이너리를 999번 실행했습니다 . 파일에 10개의 일치 항목이 있으므로 결과는 다음과 같습니다.
9990
1.06s user 0.94s system 65% cpu 3.054 total
이제 나도 테스트해봤는데..
time \
( set x58 x5e x20 x20 xfe x5a x1e xda \
x48 x20 x20 x20 x0d x20 x03 x20 \
x07 x20 x20 x20 xcd x01 x20 x20
export LC_ALL=C i=0 grep="$(IFS=\\;printf "\\$*")"
while [ "$((i+=1))" -lt 1000 ]
do cat 0002.raw; done |
tr '\0 ' ' \0' |
grep -aFo "$grep"| wc -l
)
나는 거기를 사용하고 있지만 테스트에서 완전히 사용하고 제거해도 wc -l
실행 시간에 영향을 미치지 않는 것 같습니다. 어쨌든 개수는 동일합니다. 결과는 다음과 같습니다.-caFo
wc
9990
1.56s user 1.46s system 82% cpu 3.648 total
이제 이 두 명령 세트는 동일하지 않습니다. 원하지 않는 바이트를 먼저 짜내면 더 빠르게 수행되는 것처럼 보이지만 이는 개수를 얻을 수 있지만 tr
두 번째 예에서 스위치를 추가하여-b
오프셋을 얻을 수 없다는 것을 의미합니다.....grep
time \
( set x58 x5e x20 x20 xfe x5a x1e xda \
x48 x20 x20 x20 x0d x20 x03 x20 \
x07 x20 x20 x20 xcd x01 x20 x20
export LC_ALL=C i=0 grep="$(IFS=\\;printf "\\$*")"
while [ "$((i+=1))" -lt 1000 ]
do cat 0002.raw; done |
tr '\0 ' ' \0' |
grep -baFo "$grep" | sed -n l
)
...
241133568:X^ \376Z\036\332H \r \003 \a \315\001 $
241157720:X^ \376Z\036\332H \r \003 \a \315\001 $
241181872:X^ \376Z\036\332H \r \003 \a \315\001 $
241206024:X^ \376Z\036\332H \r \003 \a \315\001 $
241230176:X^ \376Z\036\332H \r \003 \a \315\001 $
241254328:X^ \376Z\036\332H \r \003 \a \315\001 $
1.59s user 1.41s system 85% cpu 3.496 total
그래서 어떤 것을 선택하든 당신이 원하는 것이 무엇인지에 따라 달라질 것이라고 생각합니다. 수학적으로만 계산하면 tr -cd
더 나을 것입니다. 매번 다른 방법보다 0.5초 더 빠릅니다. 하지만 그렇게 일반적이지는 않으므로 기꺼이 grep
지원한다면 grep -baFo
필요할 수도 있습니다.