Я написал этот PHP-код для реализации показателя удобочитаемости Flesch-Kincaid как функции:
function readability($text) { $total_sentences = 1; // one full stop = two sentences => start with 1 $punctuation_marks = array('.', '?', '!', ':'); foreach ($punctuation_marks as $punctuation_mark) { $total_sentences += substr_count($text, $punctuation_mark); } $total_words = str_word_count($text); $total_syllable = 3; // assuming this value since I don't know how to count them $score = 206.835-(1.015*$total_words/$total_sentences)-(84.6*$total_syllables/$total_words); return $score; }
У вас есть предложения по улучшению кода? Правильно ли это? Это будет работать?
Я надеюсь, что вы можете мне помочь. Заранее спасибо!
Код выглядит отлично, насколько эвристика идет. Вот несколько моментов, которые следует учитывать, чтобы сделать предметы, которые вам нужно рассчитать, значительно сложнее для машины:
Что такое предложение?
Серьезно, что такое предложение? У нас есть периоды, но они также могут быть использованы для Ph.D., например, YMCA и других целей, не связанных с предложением. Когда вы рассматриваете восклицательные знаки, вопросительные знаки и эллипсы, вы действительно оказываете себе плохую уверенность, предполагая, что период сделает трюк. Я рассматривал эту проблему раньше, и если вы действительно хотите получить более надежное количество предложений в реальном тексте, вам нужно будет разобрать текст. Это может быть вычислительно интенсивным, трудоемким и трудно найти свободные ресурсы. В конце концов, вам все равно придется беспокоиться о частоте ошибок конкретной реализации парсера. Тем не менее, только полный синтаксический анализ скажет вам, что такое предложение, а также то, что просто используется во многих других периодах. Кроме того, если вы используете текст «в дикой природе» – например, HTML – вам также придется беспокоиться о том, что предложения заканчиваются не пунктуацией, а концами тегов. Например, многие сайты не добавляют знаки препинания к тегам h1 и h2, но они явно отличаются предложениями или фразами.
Слоги не то, что мы должны приближать
Это основной признак этой эвристики с точки зрения удобства чтения, и именно это делает ее наиболее сложной для реализации. Вычислительный анализ количества слогов в работе требует предположения о том, что предполагаемый читатель говорит на том же диалекте, что и ваш генератор подсчета слогов. Как звуки падают вокруг слога, на самом деле значительная часть того, что делает акценты акцентами. Если вы мне не верите, попробуйте посетить Ямайку когда-нибудь. Это означает, что даже если бы человек выполнял вычисления для этого вручную, это все равно было бы специфическим для диалекта.
Что такое слово?
Не восковая психолингвистическая в малейшей степени, но вы обнаружите, что слова, разделенные пробелами, и то, что концептуализируются как слова для говорящего, совершенно разные. Это сделает концепцию оценки вычислимой читаемости несколько сомнительной.
Поэтому, в конце концов, я могу ответить на ваш вопрос: «Будет ли это работать». Если вы хотите взять фрагмент текста и показать этот показатель удобочитаемости среди других показателей, чтобы предложить какую-то мыслимую добавленную стоимость, взыскательный пользователь не затронет все эти вопросы. Если вы пытаетесь сделать что-то научное или даже что-то педагогическое (так как этот счет и те, что были в нем в конечном счете предназначены), я бы не стал беспокоиться. На самом деле, если вы собираетесь использовать это, чтобы делать какие-либо предложения пользователю о том, что они создали, я был бы крайне нерешительным.
Лучший способ измерить трудности чтения текста скорее всего будет чем-то связанным с отношением низкочастотных слов к высокочастотным словам, а также количеством haxax legomena в тексте. Но я бы не стал на самом деле придумывать такую эвристику, потому что было бы очень сложно эмпирически проверить что-либо подобное.
Взгляните на класс текстовой статистики PHP на GitHub.
Пожалуйста, ознакомьтесь со следующими двумя классами и информацией об использовании. Это, безусловно, поможет вам.
Считываемость Сложный граф Тип библиотеки:
<?php class ReadabilitySyllableCheckPattern { public $probWords = [ 'abalone' => 4, 'abare' => 3, 'abed' => 2, 'abruzzese' => 4, 'abbruzzese' => 4, 'aborigine' => 5, 'acreage' => 3, 'adame' => 3, 'adieu' => 2, 'adobe' => 3, 'anemone' => 4, 'apache' => 3, 'aphrodite' => 4, 'apostrophe' => 4, 'ariadne' => 4, 'cafe' => 2, 'calliope' => 4, 'catastrophe' => 4, 'chile' => 2, 'chloe' => 2, 'circe' => 2, 'coyote' => 3, 'epitome' => 4, 'forever' => 3, 'gethsemane' => 4, 'guacamole' => 4, 'hyperbole' => 4, 'jesse' => 2, 'jukebox' => 2, 'karate' => 3, 'machete' => 3, 'maybe' => 2, 'people' => 2, 'recipe' => 3, 'sesame' => 3, 'shoreline' => 2, 'simile' => 3, 'syncope' => 3, 'tamale' => 3, 'yosemite' => 4, 'daphne' => 2, 'eurydice' => 4, 'euterpe' => 3, 'hermione' => 4, 'penelope' => 4, 'persephone' => 4, 'phoebe' => 2, 'zoe' => 2 ]; public $addSyllablePatterns = [ "([^s]|^)ia", "iu", "io", "eo($|[b-df-hj-np-tv-z])", "ii", "[ou]a$", "[aeiouym]bl$", "[aeiou]{3}", "[aeiou]y[aeiou]", "^mc", "ism$", "asm$", "thm$", "([^aeiouy])\1l$", "[^l]lien", "^coa[dglx].", "[^gq]ua[^auieo]", "dnt$", "uity$", "[^aeiouy]ie(r|st|t)$", "eings?$", "[aeiouy]sh?e[rsd]$", "iell", "dea$", "real", "[^aeiou]y[ae]", "gean$", "riet", "dien", "uen" ]; public $prefixSuffixPatterns = [ "^un", "^fore", "^ware", "^none?", "^out", "^post", "^sub", "^pre", "^pro", "^dis", "^side", "ly$", "less$", "some$", "ful$", "ers?$", "ness$", "cians?$", "ments?$", "ettes?$", "villes?$", "ships?$", "sides?$", "ports?$", "shires?$", "tion(ed)?$" ]; public $subSyllablePatterns = [ "cia(l|$)", "tia", "cius", "cious", "[^aeiou]giu", "[aeiouy][^aeiouy]ion", "iou", "sia$", "eous$", "[oa]gue$", ".[^aeiuoycgltdb]{2,}ed$", ".ely$", "^jua", "uai", "eau", "[aeiouy](b|c|ch|d|dg|f|g|gh|gn|k|l|ll|lv|m|mm|n|nc|ng|nn|p|r|rc|rn|rs|rv|s|sc|sk|sl|squ|ss|st|t|th|v|y|z)e$", "[aeiouy](b|c|ch|dg|f|g|gh|gn|k|l|lch|ll|lv|m|mm|n|nc|ng|nch|nn|p|r|rc|rn|rs|rv|s|sc|sk|sl|squ|ss|th|v|y|z)ed$", "[aeiouy](b|ch|d|f|gh|gn|k|l|lch|ll|lv|m|mm|n|nch|nn|p|r|rn|rs|rv|s|sc|sk|sl|squ|ss|st|t|th|v|y)es$", "^busi$" ]; } ?>
размере<?php class ReadabilitySyllableCheckPattern { public $probWords = [ 'abalone' => 4, 'abare' => 3, 'abed' => 2, 'abruzzese' => 4, 'abbruzzese' => 4, 'aborigine' => 5, 'acreage' => 3, 'adame' => 3, 'adieu' => 2, 'adobe' => 3, 'anemone' => 4, 'apache' => 3, 'aphrodite' => 4, 'apostrophe' => 4, 'ariadne' => 4, 'cafe' => 2, 'calliope' => 4, 'catastrophe' => 4, 'chile' => 2, 'chloe' => 2, 'circe' => 2, 'coyote' => 3, 'epitome' => 4, 'forever' => 3, 'gethsemane' => 4, 'guacamole' => 4, 'hyperbole' => 4, 'jesse' => 2, 'jukebox' => 2, 'karate' => 3, 'machete' => 3, 'maybe' => 2, 'people' => 2, 'recipe' => 3, 'sesame' => 3, 'shoreline' => 2, 'simile' => 3, 'syncope' => 3, 'tamale' => 3, 'yosemite' => 4, 'daphne' => 2, 'eurydice' => 4, 'euterpe' => 3, 'hermione' => 4, 'penelope' => 4, 'persephone' => 4, 'phoebe' => 2, 'zoe' => 2 ]; public $addSyllablePatterns = [ "([^s]|^)ia", "iu", "io", "eo($|[b-df-hj-np-tv-z])", "ii", "[ou]a$", "[aeiouym]bl$", "[aeiou]{3}", "[aeiou]y[aeiou]", "^mc", "ism$", "asm$", "thm$", "([^aeiouy])\1l$", "[^l]lien", "^coa[dglx].", "[^gq]ua[^auieo]", "dnt$", "uity$", "[^aeiouy]ie(r|st|t)$", "eings?$", "[aeiouy]sh?e[rsd]$", "iell", "dea$", "real", "[^aeiou]y[ae]", "gean$", "riet", "dien", "uen" ]; public $prefixSuffixPatterns = [ "^un", "^fore", "^ware", "^none?", "^out", "^post", "^sub", "^pre", "^pro", "^dis", "^side", "ly$", "less$", "some$", "ful$", "ers?$", "ness$", "cians?$", "ments?$", "ettes?$", "villes?$", "ships?$", "sides?$", "ports?$", "shires?$", "tion(ed)?$" ]; public $subSyllablePatterns = [ "cia(l|$)", "tia", "cius", "cious", "[^aeiou]giu", "[aeiouy][^aeiouy]ion", "iou", "sia$", "eous$", "[oa]gue$", ".[^aeiuoycgltdb]{2,}ed$", ".ely$", "^jua", "uai", "eau", "[aeiouy](b|c|ch|d|dg|f|g|gh|gn|k|l|ll|lv|m|mm|n|nc|ng|nn|p|r|rc|rn|rs|rv|s|sc|sk|sl|squ|ss|st|t|th|v|y|z)e$", "[aeiouy](b|c|ch|dg|f|g|gh|gn|k|l|lch|ll|lv|m|mm|n|nc|ng|nch|nn|p|r|rc|rn|rs|rv|s|sc|sk|sl|squ|ss|th|v|y|z)ed$", "[aeiouy](b|ch|d|f|gh|gn|k|l|lch|ll|lv|m|mm|n|nch|nn|p|r|rn|rs|rv|s|sc|sk|sl|squ|ss|st|t|th|v|y)es$", "^busi$" ]; } ?>
к<?php class ReadabilitySyllableCheckPattern { public $probWords = [ 'abalone' => 4, 'abare' => 3, 'abed' => 2, 'abruzzese' => 4, 'abbruzzese' => 4, 'aborigine' => 5, 'acreage' => 3, 'adame' => 3, 'adieu' => 2, 'adobe' => 3, 'anemone' => 4, 'apache' => 3, 'aphrodite' => 4, 'apostrophe' => 4, 'ariadne' => 4, 'cafe' => 2, 'calliope' => 4, 'catastrophe' => 4, 'chile' => 2, 'chloe' => 2, 'circe' => 2, 'coyote' => 3, 'epitome' => 4, 'forever' => 3, 'gethsemane' => 4, 'guacamole' => 4, 'hyperbole' => 4, 'jesse' => 2, 'jukebox' => 2, 'karate' => 3, 'machete' => 3, 'maybe' => 2, 'people' => 2, 'recipe' => 3, 'sesame' => 3, 'shoreline' => 2, 'simile' => 3, 'syncope' => 3, 'tamale' => 3, 'yosemite' => 4, 'daphne' => 2, 'eurydice' => 4, 'euterpe' => 3, 'hermione' => 4, 'penelope' => 4, 'persephone' => 4, 'phoebe' => 2, 'zoe' => 2 ]; public $addSyllablePatterns = [ "([^s]|^)ia", "iu", "io", "eo($|[b-df-hj-np-tv-z])", "ii", "[ou]a$", "[aeiouym]bl$", "[aeiou]{3}", "[aeiou]y[aeiou]", "^mc", "ism$", "asm$", "thm$", "([^aeiouy])\1l$", "[^l]lien", "^coa[dglx].", "[^gq]ua[^auieo]", "dnt$", "uity$", "[^aeiouy]ie(r|st|t)$", "eings?$", "[aeiouy]sh?e[rsd]$", "iell", "dea$", "real", "[^aeiou]y[ae]", "gean$", "riet", "dien", "uen" ]; public $prefixSuffixPatterns = [ "^un", "^fore", "^ware", "^none?", "^out", "^post", "^sub", "^pre", "^pro", "^dis", "^side", "ly$", "less$", "some$", "ful$", "ers?$", "ness$", "cians?$", "ments?$", "ettes?$", "villes?$", "ships?$", "sides?$", "ports?$", "shires?$", "tion(ed)?$" ]; public $subSyllablePatterns = [ "cia(l|$)", "tia", "cius", "cious", "[^aeiou]giu", "[aeiouy][^aeiouy]ion", "iou", "sia$", "eous$", "[oa]gue$", ".[^aeiuoycgltdb]{2,}ed$", ".ely$", "^jua", "uai", "eau", "[aeiouy](b|c|ch|d|dg|f|g|gh|gn|k|l|ll|lv|m|mm|n|nc|ng|nn|p|r|rc|rn|rs|rv|s|sc|sk|sl|squ|ss|st|t|th|v|y|z)e$", "[aeiouy](b|c|ch|dg|f|g|gh|gn|k|l|lch|ll|lv|m|mm|n|nc|ng|nch|nn|p|r|rc|rn|rs|rv|s|sc|sk|sl|squ|ss|th|v|y|z)ed$", "[aeiouy](b|ch|d|f|gh|gn|k|l|lch|ll|lv|m|mm|n|nch|nn|p|r|rn|rs|rv|s|sc|sk|sl|squ|ss|st|t|th|v|y)es$", "^busi$" ]; } ?>
Другой класс, который является классом алгоритма удобочитаемости, который имеет два метода для вычисления оценки:
<?php class ReadabilityAlgorithm { function countSyllable($strWord) { $pattern = new ReadabilitySyllableCheckPattern(); $strWord = trim($strWord); // Check for problem words if (isset($pattern->{'probWords'}[$strWord])) { return $pattern->{'probWords'}[$strWord]; } // Check prefix, suffix $strWord = str_replace($pattern->{'prefixSuffixPatterns'}, '', $strWord, $tmpPrefixSuffixCount); // Removed non word characters from word $arrWordParts = preg_split('`[^aeiouy]+`', $strWord); $wordPartCount = 0; foreach ($arrWordParts as $strWordPart) { if ($strWordPart <> '') { $wordPartCount++; } } $intSyllableCount = $wordPartCount + $tmpPrefixSuffixCount; // Check syllable patterns foreach ($pattern->{'subSyllablePatterns'} as $strSyllable) { $intSyllableCount -= preg_match('`' . $strSyllable . '`', $strWord); } foreach ($pattern->{'addSyllablePatterns'} as $strSyllable) { $intSyllableCount += preg_match('`' . $strSyllable . '`', $strWord); } $intSyllableCount = ($intSyllableCount == 0) ? 1 : $intSyllableCount; return $intSyllableCount; } function calculateReadabilityScore($stringText) { # Calculate score $totalSentences = 1; $punctuationMarks = array('.', '!', ':', ';'); foreach ($punctuationMarks as $punctuationMark) { $totalSentences += substr_count($stringText, $punctuationMark); } // get ASL value $totalWords = str_word_count($stringText); $ASL = $totalWords / $totalSentences; // find syllables value $syllableCount = 0; $arrWords = explode(' ', $stringText); $intWordCount = count($arrWords); //$intWordCount = $totalWords; for ($i = 0; $i < $intWordCount; $i++) { $syllableCount += $this->countSyllable($arrWords[$i]); } // get ASW value $ASW = $syllableCount / $totalWords; // Count the readability score $score = 206.835 - (1.015 * $ASL) - (84.6 * $ASW); return $score; } } ?>
// Пример: как использовать
<?php // Create object to count readability score $readObj = new ReadabilityAlgorithm(); echo $readObj->calculateReadabilityScore("Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into: electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently; with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum!"); ?>
На самом деле я не вижу никаких проблем с этим кодом. Конечно, его можно было бы оптимизировать, если бы вы действительно хотели, заменив все разные функции на один цикл подсчета. Тем не менее, я бы сильно утверждал, что это не обязательно и даже совершенно неправильно. Ваш текущий код очень читабельны и понятны, и любая оптимизация, вероятно, ухудшит ситуацию с этой точки зрения. Используйте его так, как есть, и не пытайтесь его оптимизировать, если это фактически не является узким местом производительности.