Crea un indice di leggibilità


13

L' algoritmo di leggibilità di Flesch-Kincaid dipende dalle misure del conteggio delle parole e del conteggio delle sillabe, nessuna delle quali è del tutto obiettiva o facilmente automatizzabile mediante un computer. Ad esempio, "code-golf", con il trattino, conta come una o due parole? La parola "milioni" è di due o tre sillabe? In questa attività, sarà necessario approssimarsi, poiché il conteggio esatto richiederà troppo tempo, spazio e, soprattutto, codice.

Il tuo compito è costruire il programma più piccolo possibile (cioè una funzione) in qualsiasi lingua che esegua un passaggio di lettura in inglese (si presume che sia in frasi complete) e calcolare l'indice Flesch Reading Ease con una tolleranza di otto punti (per tenere conto di variazioni nel conteggio delle sillabe e nel conteggio delle parole). Si calcola come segue:

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

Il programma deve essere allineato ai passaggi di riferimento seguenti, i cui indici sono stati calcolati utilizzando il conteggio manuale:

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!

Indice: 111,38 (64 sillabe in 62 parole in 8 frasi)

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.

Indice: 65.09 (74 sillabe in 55 parole in 2 frasi)

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.

Indice: 3,70 (110 sillabe in 71 parole in 1 frase)

Se hai altri passaggi per i quali hai contato manualmente le sillabe e le parole e calcolato l'indice, puoi mostrarle come verifica.


Può essere una funzione? O deve prendere STDIN?
Brigand,

2
Hai il conteggio delle sillabe disponibile per i 3 passaggi di esempio o solo l'indice? Se ce l'hai, il conteggio delle sillabe sarebbe utile per il confronto.
Strigoides,

Può essere una funzione. In effetti, dovrebbe essere una funzione.
Joe Z.

Risposte:


6

Perl 120 byte

#!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

I / O di esempio:

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

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

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

Il conteggio delle sillabe viene fatto assumendo che ogni gruppo di vocali sia una singola sillaba, ad eccezione delle vocali solitarie alla fine di una parola, che vengono contate solo due terzi del tempo; un euristico che sembra essere abbastanza preciso.


3

K&R c - 188 196 199 229 caratteri

Con le specifiche modificate per specificare una funzione, posso ottenere molto del sovraccarico c dal conteggio. Anche cambiando per usare l'hack di conteggio delle sillabe di Strigoides che è meglio della mia formula perfezionata ed estesa per gestire il conteggio eccessivo delle parole.

Dopo aver trovato un modo più breve per eseguire il rilevamento vocale che era tristemente basato stdchr, ho avuto l'incentivo a spremere un po 'di più dall'abominio che io ho usato in modo da non essere noioso.

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;}

La logica qui è una semplice macchina a stati. Conta solo frasi per punti, parole per stringhe di caratteri alfabetici e sillabe come stringhe di vocali (inclusa y).

Ho dovuto ingannare un po 'le costanti per farlo emergere con le cifre giuste, ma ho preso in prestito il trucco di Strigoides di sottovalutare le sillabe di una frazione fissa.

Senza golf , con commenti e alcuni strumenti di debug:

#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));
}

Output: (usando l'impalcatura della versione lunga, ma la funzione golfed.)

$ 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

carenze:

  • La logica del conteggio delle frasi è sbagliata, ma me ne vado perché solo uno degli input ha un ! o a ?.
  • La logica del conteggio delle parole tratterà le contrazioni come due parole.
  • La logica di conteggio delle sillabe tratterà le stesse contrazioni di una sillaba. Ma probabilmente sovrastima in media (ad esempio theresi contano come due e molte parole che finiscono pere verranno contate una troppa), quindi ho applicato un fattore costante di correzione del 96,9%.
  • Presuppone un set di caratteri ASCII.
  • Credo che il rilevamento delle vocali lo ammetterà [e {, che chiaramente non è giusto.
  • Un sacco di fiducia nella semantica di K&R rende questo brutto, ma ehi, è il golf del codice.

Cose da guardare:

  • Sono (momentaneamente) avanti di entrambe le soluzioni Python qui, anche se sto trascinando il perl.

  • Prendi un carico della cosa orribile che ho fatto per rilevare le vocali. Ha senso se scrivi le rappresentazioni ASCII in binario e leggi il commento nella versione lunga.


"Ho dovuto modificare la formula un po 'a mano per ottenere risultati accettabili". Questa potrebbe essere una cattiva forma.
Joe Z.

1
Ora ho almeno seguito l'esempio di Strigoides e ho apportato le modifiche sulla base di chi la comprensione del testo commette errori piuttosto che una modifica puramente ad hoc per concordare i tre casi di test.
dmckee --- ex gattino moderatore

2

Python, 202 194 188 184 171 167 caratteri

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

Innanzitutto, ottieni il numero totale di parole suddividendo lungo spazi e righe:

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

Quindi, la formula. I conteggi di frasi e sillabe sono usati solo una volta, quindi sono incorporati in questa espressione.

Le frasi sono semplicemente l'input suddiviso ., con le nuove righe filtrate:

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

Le sillabe sono costituite dall'input suddiviso lungo non vocali, con spazi rimossi. Questo sembra sopravvalutare leggermente il numero di sillabe in modo consistente, quindi dobbiamo regolarlo verso il basso (circa .98 sembra farlo):

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

202 -> 194: len(x)-2 anziché len(x[1:-1]). Rimosse le parentesi non necessarie. Reso da maiuscole e minuscole maiuscole regex

194 -> 188: il file è stato precedentemente salvato come DOS anziché come formato di file unix, causando il wc -cconteggio di righe come due caratteri. Ops.

188 -> 184: Sbarazzati di quelle cattive x for x in ... if x!=...s memorizzando il risultato intermedio e sottraendox.count(...)

184 -> 171: rimuove input / output e converte in funzione

171 -> 167: inserisci la len(x)-x.count(...)s nella formula


La tua risposta non deve includere le procedure di input e output.
Joe Z.

@JoeZeng Oh, ok. Lo trasformerò in una funzione quindi.
Strigoides,

1

Python 380 caratteri

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

Questa è una soluzione piuttosto lunga, ma funziona abbastanza bene, almeno dei 3 casi di test purché lo faccia.

Codice di prova

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()

Risultato -

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

Da qui ho usato il contatore di sillabe - Conteggio delle sillabe

Una versione più leggibile è disponibile qui


1
if len(w)>2 and w[-1]=='e'and w[-2]not in v and w[-3]in v:c-= 1Di mentalità semplice ma una buona approssimazione. Mi piace.
dmckee --- ex gattino moderatore

0

Javascript, 191 byte

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)

Il primo caso di test dà 112,9 (la risposta corretta è 111,4, con 1,5 punti)

Il secondo caso di test dà 67,4 (la risposta corretta è 65,1, disattivata di 2,3 punti)

Il terzo caso di test dà 1,7 (la risposta corretta è 3,7, con 2,0 punti)

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.