perl y operator
...June 21, 2012
사건의 발단
어느날 오후 @freenode #perl-kr 에서 일어난 일입니다.
<a3r0_> 오랜만에 퀴즈<a3r0_> 구글 입사문제인데<a3r0_> 1에서 100000 사이에 8이 몇번 나오는지 맞춰라~<a3r0_> 답은 perl 원라이너로만 받음
저는 손으로 세봤습니다. 100 까지 세는데, 한참 걸렸습니다.
8,18,28,38,48,58,68,78,80,81,82,83,84,85,86,87,88,89,9820개 (88에서 8이 두개 입니다)
이렇게 세어보고 다시 irc 화면을 봤는데..
<EnGoon> eval my $count =0; for (0..100000) { /(8)/; $count += $+;} print $count;<hongbot> 799944<a3r0_> 구글 입사 불합격 하셨습니다.<ascendo> for i in $(seq 1 100000); do echo $i; done | egrep '8' | wc -l # syntax error
떡밥이 흥하질 않자 a3r0
님이 정답을 공개해 주셧습니다.
<a3r0_> $ perl -E 'for(1..100000) { $c+=@{[$_ =~ m/8/g]} }; say $c'<a3r0_> 50000<a3r0_> $ perl -E 'for(1..100000) { $c+=(tr/8//) }; say $c'<a3r0_> 50000
이렇게 묻히나 싶었는데, 뒤늦게 보신 nol2ter_work
님의 bash oneliner
<nol2ter_work> 오홍.. bash 로는.. expr `echo {1..100000} | sed -r "s/[^8]//g" | wc -m` - 1 로 되네영..<a3r0_> python으로 해보셈
여기서 python 의 대반격
<nol2ter_work> 피똥으로.. str(range(100000)).count('8')<nol2ter_work> 아.. 이건 편법일라나요 캬캬캬<a3r0_> str 함수가 문자열 이어붙여주나여?<nol2ter_work> >>> str(range(100000)).count('8')<nol2ter_work> 50000<nol2ter_work> 라고 나오긴 하네용<a3r0_> 오<jeen___> 피똥이 갑이네..<jeen___> 피똥배워야지...
분위기가 술렁이기 시작했습니다.
파이썬으로 저렇게 그레이스풀한 방법이 잇엇나 싶기도 했습니다.
거기에 더해 진사마
는 파이썬으로 갈아탈 준비를 마친 상태.
<a3r0_> say "@{[0..100000]}"=~y/8//<a3r0_> str(range(100000)).count('8')<a3r0_> 2글자 승?<a3r0_> say 빼면 6글자 승? [13:40]<a3r0_> $ perl -E 'say "@{[0..100000]}"=~y/8//'<a3r0_> 50000<a3r0_> 줄이기 최종버젼은 "@{[0..1E5]}"=~y/8//<nol2ter_work> 달달달
찰나 a3r0
님의 신의 한수
결국 1E5
까지쓰며 더 줄일 수 없도록 만들었습니다.
<jeen___> 1E5 ㅋㅋㅋㅋ
저만 여기서 터진게 아니엇습니다.
이때, 원라이너의 귀재 pung96
님의 등장
*** pung96 (~pung96@46.162.162.115) has joined channel #perl-kr<a3r0_> 원라이너의 귀재 pung96님 오셨
같은 문제를 내어 봤는데 역시나 금방 답이 나오더군요.
<pung96> 그냥,, 초 단순하게 생각하면,,<pung96> map{$s+=()=/8/g}1..100000;say$s 이럼 되는데
이쯤에서 짧은 답안 공개
<a3r0_> "@{[0..1E5]}"=~y/8//<pung96> 헐,<pung96> 1E5 ...
ㅋㅋㅋ 1E5
계속되는 덕질
<a3r0_> map{$s+=()=/8/g}1..100000<a3r0_> map{$s+=@{[/8/g]}}1..100000<pung96> map{$s+=y/8//} 이럼,, 좀더 짧아지는군요.<a3r0_> map{$s+=y/8//}1..1E5<a3r0_> "@{[1..1E5]}"=~y/8//
결국 pung96
님의 타이기록
<pung96> map$s+=y/8//,1..1E5
pung96
님의 신기록!
저는 이미 예전에 gg
<jeen___> use Alias ( map => m, print => p );<pung96> jeen___: ++
폭풍같은 시간이었습니다.
분석
"@{[0..1E5]}"=~y/8//; # 50000
아.. 아릅답습니다.
먼저 y
operator 를 perldoc
에서 찾아보면,
The transliteration operator. Same as tr///. See Quote and Quote-like Operators in perlop.
tr
operator 와 같다고 나옵니다.
tr
의미는 Transliteration(바꿔 씀) 입니다.
tr/SEARCHLIST/REPLACEMENTLIST/cdsr
cdsr
modifier 는 perldoc
에서 못찾았습니다.
그래서 검색했더니 아래와 같은 내용이 있어서 붙입니다.
c - is used to specify that the SEARCHLIST character set is complementedd - is used to delete found but not replaced characterss - is used to specify that the sequences of characters that were transliterated to the same character are squashed down to a singleinstance of the characterc Complement the SEARCHLIST.d Delete found but unreplaced characters.s Squash duplicate replaced characters.
예제
$ARGV[1] =~ tr/A-Z/a-z/; # canonicalize to lower case$cnt = tr/*/*/; # count the stars in $_$cnt = $sky =~ tr/*/*/; # count the stars in $sky$cnt = tr/0-9//; # count the digits in $_tr/a-zA-Z//s; # bookkeeper -> bokeper($HOST = $host) =~ tr/a-z/A-Z/;tr/a-zA-Z/ /cs; # change non-alphas to single spacetr [\200-\377][\000-\177]; # delete 8th bit
tr|y
operator 는 SEARCHLIST
가 매칭된 갯수를 반환하는 걸
알겠습니다.
"@{[0..1E5]}"=~y/8//; # 50000
"@{[0..1E5]}"
1E5
는 10의 5 제곱입니다. 해서 -> 1..100000@{[]}
는 array 를 reference 하고 다시 dereference 하는 과정입니다. 이유는 문자열상수 안에서 perl code 를 evaluate 하고 다시 집어넣는 보간(interpolation) 하기 위한 꼼수 입니다.@{[1..100000]}
은(1, 2, 3, ..., 100000)
을 가지고 있는 array 입니다."(1,2,3,...,100000)"
array 가"
로 묶여 있으면- ”@{[0..1E5]}” 는 ‘1 2 3 4 … 100000’ 이 됩니다.
'1 2 3 ... 100000'=~y/8//;
- 문자열
1 2 3 ... 100000
에8
이 몇번 나오는지 돌려줍니다.
오늘도 즐거운 하루중입니다.