1<?php
2/**
3 * Readability Analysis Plugin for DokuWiki
4 *
5 * @author  Andreas Gohr <andi@splitbrain.org>
6 * @author  Dave Child <dave@ilovejackdaniels.com>
7 * @link    http://www.ilovejackdaniels.com/resources/readability-score/
8 * @license GPL 2
9 */
10
11
12$text = $_REQUEST['html'].'. ';
13$text = preg_replace('!</(li|h[1-5])>!i','. ',$text); //make sentences from those tags
14$text = strip_tags($text);
15
16$gf = gunning_fog_score($text);
17$fs = calculate_flesch($text);
18$fg = calculate_flesch_grade($text);
19$rt = calculate_readingtime($text);
20
21echo '<b>Readability Analysis</b>';
22echo '<ul>';
23printf('<li><div class="li"><b>Gunning-Fog Score:</b> %.2f ',$gf);
24if($gf < 12){
25    echo '(very good)';
26}elseif($gf < 15){
27    echo '(okay)';
28}else{
29    echo '(bad)';
30}
31echo ' lower is better';
32echo '</div></li>';
33printf('<li><div class="li"><b>Flesch-Kincaid Score:</b> %.2f ',$fs);
34if($fs < 50){
35    echo '(bad)';
36}elseif($fs < 80){
37    echo '(okay)';
38}else{
39    echo '(very good)';
40}
41echo ' higher is better';
42echo '</div></li>';
43printf('<li><div class="li"><b>Flesch-Kincaid Grade:</b> %.2f ',$fg);
44if($fg < 10){
45    echo '(very good)';
46}elseif($fg < 18){
47    echo '(okay)';
48}else{
49    echo '(bad)';
50}
51echo ' lower is better';
52echo '</div></li>';
53echo '<li><div class="li"><b>Estimated reading time:</b> '.$rt.'</div></li>';
54echo '</ul>';
55
56/**
57 * Calculate estimated reading time
58 *
59 * @author Brian Cray
60 * @link http://briancray.com/2010/04/09/estimated-reading-time-web-design/
61 */
62function calculate_readingtime($text){
63    $word = str_word_count($text);
64    $m = floor($word / 200);
65    $s = floor($word % 200 / (200 / 60));
66    return "$m:$s";
67}
68
69/**
70 * Calculate the Gunning-Fog score
71 *
72 * @author  Dave Child <dave@ilovejackdaniels.com>
73 */
74function gunning_fog_score($text) {
75    return ((average_words_sentence($text) +
76             percentage_number_words_three_syllables($text)) * 0.4);
77}
78
79/**
80 * Calculate the Flesch-Kinkaid reading ease score
81 *
82 * @author  Dave Child <dave@ilovejackdaniels.com>
83 */
84function calculate_flesch($text) {
85    return (206.835 - (1.015 * average_words_sentence($text)) -
86            (84.6 * average_syllables_word($text)));
87}
88
89/**
90 * Calculate the Flesch-Kinkaid Grade level
91 *
92 * @author  Dave Child <dave@ilovejackdaniels.com>
93 */
94function calculate_flesch_grade($text) {
95    return ((.39 * average_words_sentence($text)) +
96            (11.8 * average_syllables_word($text)) - 15.59);
97}
98
99/**
100 * Calculate the percentage of words with more than 3 syllables
101 *
102 * @author  Dave Child <dave@ilovejackdaniels.com>
103 */
104function percentage_number_words_three_syllables($text) {
105    $syllables = 0;
106    $words = explode(' ', $text);
107    for ($i = 0; $i < count($words); $i++) {
108        if (count_syllables($words[$i]) > 2) {
109            $syllables ++;
110        }
111    }
112    $score = number_format((($syllables / count($words)) * 100));
113
114    return ($score);
115}
116
117/**
118 * Calculate the ratio of words to sentences
119 *
120 * @author  Dave Child <dave@ilovejackdaniels.com>
121 */
122function average_words_sentence($text) {
123    $sentences = strlen(preg_replace('/[^\.!?]/', '', $text));
124    $words = strlen(preg_replace('/[^ ]/', '', $text));
125    if($sentences == 0) $sentences = 1;
126    return ($words/$sentences);
127}
128
129/**
130 * Calculate the average number of syllables per word
131 *
132 * @author  Dave Child <dave@ilovejackdaniels.com>
133 */
134function average_syllables_word($text) {
135    $words = explode(' ', $text);
136    $syllables = 0;
137    for ($i = 0; $i < count($words); $i++) {
138        $syllables = $syllables + count_syllables($words[$i]);
139    }
140    return ($syllables/count($words));
141}
142
143/**
144 * Count the number of syllables in the given word
145 *
146 * @author  Dave Child <dave@ilovejackdaniels.com>
147 */
148function count_syllables($word) {
149
150    $subsyl = Array(
151        'cial',
152        'tia',
153        'cius',
154        'cious',
155        'giu',
156        'ion',
157        'iou',
158        'sia$',
159        '.ely$'
160    );
161
162    $addsyl = Array(
163        'ia',
164        'riet',
165        'dien',
166        'iu',
167        'io',
168        'ii',
169        '[aeiouym]bl$',
170        '[aeiou]{3}',
171        '^mc',
172        'ism$',
173        '([^aeiouy])\1l$',
174        '[^l]lien',
175        '^coa[dglx].',
176        '[^gq]ua[^auieo]',
177        'dnt$'
178    );
179
180    // Based on Greg Fast's Perl module Lingua::EN::Syllables
181    $word = preg_replace('/[^a-z]/is', '', strtolower($word));
182    $word_parts = preg_split('/[^aeiouy]+/', $word);
183    $valid_word_parts = array();
184    foreach ($word_parts as $key => $value) {
185        if ($value <> '') {
186            $valid_word_parts[] = $value;
187        }
188    }
189
190    $syllables = 0;
191    foreach ($subsyl as $syl) {
192        if (strpos($word, $syl) !== false) {
193            $syllables--;
194        }
195    }
196    foreach ($addsyl as $syl) {
197        if (strpos($word, $syl) !== false) {
198            $syllables++;
199        }
200    }
201    if (strlen($word) == 1) {
202        $syllables++;
203    }
204    $syllables += count($valid_word_parts);
205    $syllables = ($syllables == 0) ? 1 : $syllables;
206    return $syllables;
207}
208
209
210