challenge コード中の文字の頻度分析

プログラムコード中の文字の頻度は言語によって相当にばらつきがあると思います。ある言語はピリオドが頻出するとか、別の言語はカッコの頻出頻度が高い、とか。そこで、

  • 文字の頻度解析をするプログラムを作成し、
  • 適当なプログラムに対して実行し、結果を出力して、そのような頻度になっている理由を教えてください。

(その言語で書かれた「典型的な」プログラムコード、といえるようなものがあると良いのですが・・)

簡単すぎるという方は、複数文字にしてみたり単語の頻度にしてみてください。

参考;Wikipedia 頻度分析

http://ja.wikipedia.org/wiki/%E9%A0%BB%E5%BA%A6%E5%88%86%E6%9E%90

出題者です。 こちらで用意していた回答は awk を使ったものでした。一応解説すると、組み込み変数FSを空にし、1行単位の文字毎に連想配列に格納しています。

1
2
3
4
5
6
7
8
9
# 1文字版
BEGIN { FS="" }
{ for (i=1; i<=NF; i++) ht[$i]++}
END { for (c in ht) print ht[c],c }

# 3文字版
BEGIN { FS="" }
{ for (i=1; i<=NF-2; i++) { ht[$i$(i+1)$(i+2)]++}}
END { for (c in ht) print ht[c],c }

Posted feedbacks - Scheme

Gauche (Scheme) で書きました。
Gauche 付属の srfi-42.scm を分析してみました。

#\space = 11142 / 38818 : 28.70 %
#\e = 2396 / 38818 : 6.17 %
#\( = 1640 / 38818 : 4.22 %
#\) = 1634 / 38818 : 4.20 %
#\r = 1492 / 38818 : 3.84 %
#\t = 1419 / 38818 : 3.65 %
#\= = 1391 / 38818 : 3.58 %
#\a = 1284 / 38818 : 3.30 %
#\s = 1280 / 38818 : 3.29 %
#\i = 1194 / 38818 : 3.07 %
...

やっぱり括弧がちょっと多めかな。
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
(define make-char-counter (lambda ()
  (let ((ls '()))
    (lambda (c)
      (if (char? c)
        (set! ls
          (let loop ((li ls) (flag #f) (ret '()))
            (if (pair? li)
              (if (char=? c (caar li))
                (loop (cdr li) #t (cons (cons c (+ 1 (cdar li))) ret))
                (loop (cdr li) flag (cons (car li) ret)))
              (if flag ret (cons (cons c 1) ret)))))
        ls)))))

(define count-char (lambda (file)
  (call-with-input-file file
    (lambda (in)
      (let ((counter (make-char-counter)))
        (let loop ((c (read-char in)))
          (if (eof-object? c)
            (counter #f)
            (begin (counter c) (loop (read-char in))))))))))

(define main (lambda (args)
  (let* ((count (sort (count-char (cadr args)) (lambda (x y) (> (cdr x) (cdr y)))))
      (total (fold (lambda (p total) (+ (cdr p) total)) 0 count)))
    (for-each
      (lambda (p)
        (format #t "~s = ~d / ~d : ~d.~2,'0d %" (car p) (cdr p) total
          (inexact->exact (truncate (* (/ (cdr p) total) 100)))
          (remainder (inexact->exact (truncate (* (/ (cdr p) total) 10000))) 100))
        (newline))
      count))
  0))

Gauche で書きました。 Gauche に添付されている srfi-*.scm で調べてみると:

#\space:        9865(20.78%)
#\e:    3536(7.449%)
#\t:    3154(6.644%)
#\a:    2160(4.550%)
#\i:    2159(4.548%)
#\-:    2057(4.333%)
#\(:    1872(3.943%)
#\):    1872(3.943%)
#\n:    1834(3.863%)

括弧が目立って多いかと思いきや、頻度の高いアルファベットやハイフンよりも少ないという結果になっていました(それでも C 言語の 1.5~2.0 % 程度というのに比べると十分多いのかもしれませんが)。

結局、一番多いのは字下げのための空白でした。よく訓練された Lisper には括弧は見えない云々。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
(use srfi-1)
(use gauche.collection)

(define (main args)
  (call-with-input-file (second args)
    (lambda (port)
      (let* ((ts (port->list read-char port))
         (lt (length ts))
         (tss (group-collection ts))
         (hist (sort (map (lambda (ts)
                (let ((l (length ts)))
                  (list (car ts) l (/. (* l 100) lt))))
                  tss)
             (lambda (x y) (> (second x) (second y))))))
    (for-each (cut apply format #t "~S:\t~A(~,,,,5A%)~%" <>) hist)))))

Index

Feed

Other

Link

Pathtraq

loading...