Erstellen Sie einen Lesbarkeitsindex

13

Der Flesch-Kincaid-Lesbarkeitsalgorithmus hängt von den Maßen der Wortzahl und der Silbenzahl ab, von denen keines vollständig objektiv oder mit einem Computer leicht automatisierbar ist. Zählt beispielsweise "Code-Golf" mit dem Bindestrich als ein oder zwei Wörter? Ist das Wort "Million" zwei oder drei Silben? In dieser Aufgabe müssen Sie eine Annäherung vornehmen, da das genaue Zählen zu viel Zeit, Platz und vor allem Code beansprucht.

Ihre Aufgabe ist es, das kleinstmögliche Programm (dh eine Funktion) in einer beliebigen Sprache zu erstellen, die eine englische Lesepassage (angenommen in vollständigen Sätzen) enthält, und den Flesch Reading Ease-Index mit einer Toleranz von acht Punkten zu berechnen (zu berücksichtigen) Variationen bei der Silbenzählung und der Wortzählung). Es wird wie folgt berechnet:

FRE = 206.835 - 1.015 * (words per sentence) - 84.6 * (syllables per word)

Ihr Programm muss an den folgenden Referenzpassagen ausgerichtet sein, deren Indizes mit manueller Zählung berechnet wurden:

I would not, could not, in the rain.
Not in the dark, not on a train.
Not in a car, not in a tree.
I do not like them, Sam, you see.
Not in a house, not in a box.
Not with a mouse, not with a fox.
I will not eat them here or there.
I do not like them anywhere!

Index: 111,38 (64 Silben in 62 Wörtern in 8 Sätzen)

It was a bright cold day in April, and the clocks were striking thirteen.
Winston Smith, his chin nuzzled into his breast in an effort to escape
the vile wind, slipped quickly through the glass doors of Victory Mansions,
though not quickly enough to prevent a swirl of gritty dust from entering
along with him.

Index: 65.09 (74 Silben in 55 Wörtern in 2 Sätzen)

When in the Course of human events, it becomes necessary for one people to
dissolve the political bands which have connected them with another, and to
assume among the powers of the earth, the separate and equal station to
which the Laws of Nature and of Nature's God entitle them, a decent respect
to the opinions of mankind requires that they should declare the causes
which impel them to the separation.

Index: 3.70 (110 Silben in 71 Wörtern in 1 Satz)

Wenn Sie andere Passagen haben, für die Sie die Silben und Wörter manuell gezählt und den Index berechnet haben, können Sie diese als Verifikation anzeigen.

Joe Z.
quelle
Kann es eine Funktion sein? Oder muss es STDIN nehmen?
Brigant
2
Haben Sie die Anzahl der verfügbaren Silben für die drei Beispielpassagen oder nur den Index? Wenn Sie es haben, wäre die Silbenzahl zum Vergleich praktisch.
Strigoides
Es kann eine Funktion sein. In der Tat sollte es eine Funktion sein.
Joe Z.

Antworten:

6

Perl 120 Bytes

#!perl -pa0
s@\w+|([.!?])@$s+=$#-,lc($&)=~s![aeiou]+\B|([aeiouy]$)!$y+=1-$#-/3!ger@ge}
{$_=206.835-1.015*@F/$s-84.6*$y/@F

Beispiel I / O:

$ perl flesch-kincaid.pl < input1.dat
110.730040322581

$ perl flesch-kincaid.pl < input2.dat
65.6097727272728

$ perl flesch-kincaid.pl < input2.dat
1.71366197183096

Das Zählen von Silben erfolgt unter der Annahme, dass jeder Vokalcluster eine einzige Silbe ist, mit Ausnahme von einsamen Vokalen am Ende eines Wortes, die nur zwei Drittel der Zeit gezählt werden. eine Heuristik, die ziemlich genau zu sein scheint.

primo
quelle
3

K & R c - 188 196 199 229 Zeichen

Wenn die Spezifikation geändert wird, um eine Funktion anzugeben, kann ich einen Großteil des c-Overheads aus der Zählung herausholen. Es wurde auch geändert, um Strigoides 'Silbenzähl-Hack zu verwenden, der besser ist als meine Formeloptimierung und erweitert, um das Überzählen von Wörtern zu behandeln.

Nachdem ich einen kürzeren Weg gefunden hatte, um die stdchrVokalerkennung durchzuführen, der leider zugrunde lag , hatte ich den Anreiz, ein paar mehr aus dem Gräuel herauszupressen, den ich benutzt hatte, damit ich mich nicht langweilen musste.

d,a,v,s,t,w;float R(char*c){for(;*c;++c){s+=*c=='.';if(isalpha(*c)){
w+=!a++;d=(*c&30)>>1;if(*c&1&(d==7|((!(d&1))&(d<6|d>8)))){t+=!v++;}
else v=0;}else v=a=0;}return 206.835-1.*w/s-82.*t/w;}

Die Logik hier ist eine einfache Zustandsmaschine. Es werden nur Sätze nach Punkten, Wörter nach Buchstabenfolgen und Silben als Vokalfolgen (einschließlich y) gezählt.

Ich musste die Konstanten ein wenig verändern, um die richtigen Zahlen zu erhalten, aber ich habe mir Strigoides 'Trick geliehen, die Silben nur um einen festen Bruchteil zu unterzählen.

Ohne Golf , mit Kommentaren und einigen Debugging-Tools:

#include <stdlib.h>
#include <stdio.h>
d,a,/*last character was alphabetic */
  v,/*lastcharacter was a vowel */
  s, /* sentences counted by periods */
  t, /* syllables counted by non-consequtive vowels */
  w; /* words counted by non-letters after letters */
float R/*eadability*/(char*c){
  for(;*c;++c){
    s+=*c=='.';
    if(isalpha(*c)){ /* a letter might mark the start of a word or a
               vowel string */
      w+=!a++; /* It is only the start of a word if the last character
              wasn't a letter */
      /* Extract the four bits of the character that matter in determining
       * vowelness because a vowel might mark a syllable */
      d=(*c&30)>>1;
      if( *c&1  & ( d==7 | ( (!(d&1)) & (d<6|d>8) ) ) 
      ) { /* These bits 7 or even and not 6, 8 make for a
         vowel */
    printf("Vowel: '%c' (mangled as %d [0x%x]) counts:%d\n",*c,d,d,!v);
    t+=!v++;
      } else v=0; /* Not a vowel so set the vowel flag to zero */
    }else v=a=0; /* this input not alphabetic, so set both the
            alphabet and vowel flags to zero... */
  }
  printf("Syllables: %3i\n",t);
  printf("Words:     %3i       (t/w) = %f\n",w,(1.0*t/w));
  printf("Sentences: %3i       (w/s) = %f\n",s,(1.0*w/s));
  /* Constants tweaked here due to bad counting behavior ...
   * were:       1.015     84.6 */
  return 206.835-1.   *w/s-82. *t/w;
}
main(c){
  int i=0,n=100;
  char*buf=malloc(n);
  /* Suck in the whole input at once, using a dynamic array for staorage */
  while((c=getc(stdin))!=-1){
    if(i==n-1){ /* Leave room for the termination */
      n*=1.4;
      buf=realloc(buf,n);
      printf("Reallocated to %d\n",n);
    }
    buf[i++]=c;
    printf("%c %c\n",c,buf[i-1]);
  }
  /* Be sure the string is terminated */
  buf[i]=0;
  printf("'%s'\n",buf);
  printf("%f\n",R/*eadability*/(buf));
}

Ausgabe: (mit dem Gerüst aus der langen Version, aber die Golffunktion.)

$ gcc readability_golf.c
readability_golf.c:1: warning: data definition has no type or storage class
$ ./a.out < readability1.txt 
'I would not, could not, in the rain.
Not in the dark, not on a train.
Not in a car, not in a tree.
I do not like them, Sam, you see.
Not in a house, not in a box.
Not with a mouse, not with a fox.
I will not eat them here or there.
I do not like them anywhere!
'
104.074631    
$ ./a.out < readability2.txt
'It was a bright cold day in April, and the clocks were striking thirteen.
Winston Smith, his chin nuzzled into his breast in an effort to escape
the vile wind, slipped quickly through the glass doors of Victory Mansions,
though not quickly enough to prevent a swirl of gritty dust from entering
along with him.
'
63.044090
$ ./a.out < readability3.txt 
'When in the Course of human events, it becomes necessary for one people to
dissolve the political bands which have connected them with another, and to
assume among the powers of the earth, the separate and equal station to
which the Laws of Nature and of Nature's God entitle them, a decent respect
to the opinions of mankind requires that they should declare the causes
which impel them to the separation.
'
-1.831667

Mängel:

  • Die Satzzähllogik ist falsch, aber ich komme damit durch, weil nur einer der Eingänge ein !oder ein hat? .
  • Die Wortzähllogik behandelt Kontraktionen als zwei Wörter.
  • Die Silbenzähllogik behandelt dieselben Kontraktionen wie eine Silbe. Aber wahrscheinlich werden im Durchschnitt zu thereviele Wörter gezählt (zum Beispiel werden zwei und viele Wörter gezählt, die auf enden)e , werden eins zu viele gezählt), also habe ich einen konstanten Korrekturfaktor von 96,9% angewendet.
  • Nimmt einen ASCII-Zeichensatz an.
  • Ich glaube, die Vokalerkennung wird dies zugeben [und{ das ist eindeutig nicht richtig.
  • Viel Vertrauen in die K & R-Semantik macht dies hässlich, aber hey, es ist Code-Golf.

Dinge zu sehen:

  • Ich bin hier (momentan) beiden Python-Lösungen voraus, auch wenn ich dem Perl nachlaufe.

  • Holen Sie sich eine Ladung von dem schrecklichen, was ich getan habe, um Vokale zu entdecken. Es ist sinnvoll, wenn Sie die ASCII-Darstellungen in Binärform schreiben und den Kommentar in der Langfassung lesen.

dmckee --- Ex-Moderator Kätzchen
quelle
"Ich musste die Formel ein wenig von Hand ändern, um akzeptable Ergebnisse zu erzielen." Dies kann eine schlechte Form sein.
Joe Z.
1
Ich bin jetzt zumindest Strigoides 'Vorbild gefolgt und habe die Anpassungen eher auf der Grundlage dessen vorgenommen, wer das Textverständnis fehlerhaft macht, als durch eine reine Ad-hoc- Optimierung, um die drei Testfälle in Übereinstimmung zu bringen.
dmckee --- Ex-Moderator Kätzchen
2

Python, 202 194 188 184 171 167 Zeichen

import re
def R(i):r=re.split;w=len(r(r'[ \n]',i));s=r('\\.',i);y=r('[^aeiou](?i)+',i);return 206.835-1.015*w/(len(s)-s.count('\n'))-84.6*(len(y)-y.count(' ')-2)*.98/w

Ermitteln Sie zunächst die Gesamtzahl der Wörter, indem Sie Leerzeichen und Zeilenumbrüche aufteilen:

w=len(r(r'[ \n]',i))

Dann die Formel. Satz- und Silbenzahlen werden nur einmal verwendet und sind daher in diesen Ausdruck eingebettet.

Sätze sind einfach die Eingabe, zusammen .mit herausgefilterten Zeilenumbrüchen:

s=r('\\.',i);s=len(s)-s.count('\n')

Silben bestehen aus der Eingabe entlang von Nicht-Vokalen, wobei Leerzeichen entfernt werden. Dies scheint die Anzahl der Silben durchweg leicht zu überschätzen, so dass wir sie nach unten korrigieren müssen (ungefähr .98 scheint dies zu tun):

y=r('[^aeiou](?i)+',i);y=len(y)-y.count(' ')-2;

202 -> 194: len(x)-2 eher als len(x[1:-1]). Unnötige Klammern entfernt. Regex für Silben ohne Berücksichtigung der Groß- und Kleinschreibung

194 -> 188: Die Datei wurde zuvor im wc -cDOS- und nicht im UNIX- Dateiformat gespeichert, sodass Zeilenumbrüche als zwei Zeichen gezählt wurden. Hoppla.

188 -> 184: Werden Sie diese unangenehmen x for x in ... if x!=...s los, indem Sie das Zwischenergebnis speichern und subtrahierenx.count(...)

184 -> 171: Ein- / Ausgabe entfernen und in Funktion konvertieren

171 -> 167: Fügen Sie das len(x)-x.count(...)s in die Formel ein

Strigoides
quelle
Ihre Antwort muss nicht die Eingabe- und Ausgabeverfahren enthalten.
Joe Z.
@ JoeZeng Oh, okay. Ich werde es dann in eine Funktion verwandeln.
Strigoides
1

Python 380 Zeichen

import re
def t(p):
 q=lambda e: e!=''
 w=filter(q,re.split('[ ,\n\t]',p))
 s=filter(q,re.split('[.?!]',p))
 c=len(w)*1.0
 f=c/len(s)
 return w,f,c
def s(w):
 c= len(re.findall(r'([aeiouyAEIOUY]+)',w))
 v='aeiouAEIOU'
 if len(w)>2 and w[-1]=='e'and w[-2]not in v and w[-3]in v:c-= 1
 return c
def f(p):
 w,f,c=t(p)
 i=0
 for o in w:
  i+=s(o)
 x=i/c
 return 206.835-1.015*f-84.6*x

Dies ist eine ziemlich lange Lösung, aber sie funktioniert gut genug, zumindest in den 3 Testfällen, sofern dies der Fall ist.

Code testen

def test():
 test_cases=[['I would not, could not, in the rain.\
        Not in the dark, not on a train.\
        Not in a car, not in a tree.\
        I do not like them, Sam, you see.\
        Not in a house, not in a box.\
        Not with a mouse, not with a fox.\
        I will not eat them here or there.\
        I do not like them anywhere!', 111.38, 103.38, 119.38],\
        ['It was a bright cold day in April, and the clocks were striking thirteen.\
        Winston Smith, his chin nuzzled into his breast in an effort to escape\
        the vile wind, slipped quickly through the glass doors of Victory Mansions,\
        though not quickly enough to prevent a swirl of gritty dust from entering\
        along with him.', 65.09, 57.09, 73.09],\
        ["When in the Course of human events, it becomes necessary for one people to\
        dissolve the political bands which have connected them with another, and to\
        assume among the powers of the earth, the separate and equal station to\
        which the Laws of Nature and of Nature's God entitle them, a decent respect\
        to the opinions of mankind requires that they should declare the causes\
        which impel them to the separation.", 3.70, -4.70, 11.70]]
 for case in test_cases:
  fre= f(case[0])
  print fre, case[1], (fre>=case[2] and fre<=case[3])

if __name__=='__main__':
 test()

Ergebnis -

elssar@elssar-laptop:~/code$ python ./golf/readibility.py
108.910685484 111.38 True
63.5588636364 65.09 True
-1.06661971831 3.7 True

Ich habe den Silbenzähler von hier verwendet - Zählen von Silben

Eine besser lesbare Version finden Sie hier

Elssar
quelle
1
if len(w)>2 and w[-1]=='e'and w[-2]not in v and w[-3]in v:c-= 1Einfältig, aber eine gute Annäherung. Ich mag das.
dmckee --- Ex-Moderator Kätzchen
0

Javascript, 191 Bytes

t=prompt(q=[]);s=((t[m="match"](/[!?.]+/g)||q)[l="length"]||1);y=(t[m](/[aeiouy]+/g)||q)[l]-(t[m](/[^aeiou][aeiou][s\s,'.?!]/g)||q)[l]*.33;w=(t.split(/\s+/g))[l];alert(204-1.015*w/s-84.5*y/w)

Erster Testfall ergibt 112,9 (richtige Antwort ist 111,4, ab 1,5 Punkte)

Zweiter Testfall ergibt 67,4 (richtige Antwort ist 65,1, Abweichung um 2,3 Punkte)

Dritter Testfall ergibt 1,7 (richtige Antwort ist 3,7, ab 2,0 Punkte)

SuperJedi224
quelle