Zbuduj wskaźnik czytelności


13

Flesch-Kincaid czytelność algorytm zależy od środków liczby słów i liczą sylaby, z których żadna nie jest całkowicie obiektywne, lub łatwe do zautomatyzowania użycia komputera. Na przykład, czy „golf golfowy” z łącznikiem liczy się jako jedno słowo lub dwa? Czy słowo „milion” to dwie lub trzy sylaby? W tym zadaniu konieczne będzie przybliżenie, ponieważ dokładne liczenie zajmie zbyt dużo czasu, miejsca i, co najważniejsze, kodu.

Twoim zadaniem jest zbudowanie najmniejszego możliwego programu (tj. Funkcji) w dowolnym języku, który zajmie fragment czytania w języku angielskim (zakłada się, że jest w pełnych zdaniach), i obliczyć wskaźnik łatwości czytania Flescha z tolerancją ośmiu punktów (aby uwzględnić różnice w liczeniu sylab i liczeniu słów). Oblicza się go w następujący sposób:

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

Twój program musi być dostosowany do poniższych fragmentów referencyjnych, których wskaźniki zostały obliczone przy użyciu zliczania ręcznego:

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!

Indeks: 111,38 (64 sylaby w 62 słowach w 8 zdaniach)

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.

Indeks: 65,09 (74 sylaby w 55 słowach w 2 zdaniach)

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.

Indeks: 3,70 (110 sylab w 71 słowach w 1 zdaniu)

Jeśli masz inne fragmenty, dla których ręcznie policzyłeś sylaby i słowa i obliczyłeś indeks, możesz pokazać je jako weryfikację.


Czy to może być funkcja? Czy to musi mieć STDIN?
Brigand

2
Czy masz dostępną liczbę sylab dla 3 przykładowych fragmentów, czy tylko dla indeksu? Jeśli go masz, liczba sylab byłaby przydatna do porównania.
Strigoides,

To może być funkcja. W rzeczywistości powinna to być funkcja.
Joe Z.

Odpowiedzi:


6

Perl 120 bajtów

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

Przykładowe 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

Zliczanie sylab odbywa się przy założeniu, że każda grupa samogłosek jest pojedynczą sylabą, z wyjątkiem samotnych samogłosek na końcu słowa, które są liczone tylko w dwóch trzecich przypadków; heurystyka, która wydaje się dość dokładna.


3

K&R c - 188 196 199 229 znaków

Po zmianie specyfikacji w celu określenia funkcji mogę uzyskać dużo c narzutu z licznika. Zmieniłem się również, aby użyć hakerskiego liczenia sylab Strigoidesa, co jest lepsze niż moje ulepszenie formuły i rozszerzone, aby poradzić sobie z przeliczaniem słów.

Po tym, jak znalazłem krótszy sposób na wykrycie samogłoski, na którym niestety opierałem się stdchr, miałem motywację, aby wycisnąć jeszcze więcej z nieco kręcącej się obrzydliwości, której używałem, aby nie musiałem się nudzić.

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

Logika tutaj jest prostą maszyną stanu. Zlicza zdania według kropek, słowa według ciągów znaków alfabetycznych, a sylaby jako ciąg samogłosek (w tym y).

Musiałem trochę podważyć stałe, aby uzyskać właściwe liczby, ale pożyczyłem sztuczkę Strigoidesa polegającą na tym, że nie doceniłem sylab o ustalony ułamek.

Bez golfa , z komentarzami i niektórymi narzędziami do debugowania:

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

Wyjście: (przy użyciu rusztowania z długiej wersji, ale funkcja gry w golfa).

$ 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

Niedociągnięcia:

  • Logika liczenia zdań jest niepoprawna, ale mi się to udaje, ponieważ tylko jedno z wejść ma a !lub a ?.
  • Logika liczenia słów potraktuje skurcze jako dwa słowa.
  • Logika zliczania sylaby potraktuje te same skurcze jak jedną sylabę. Ale prawdopodobnie przecenia się średnio (na przykład thereliczy się jako dwa, a wiele słów kończących się ebędzie liczonych o jeden za dużo), więc zastosowałem stały współczynnik korekty 96,9%.
  • Zakłada zestaw znaków ASCII.
  • Wierzę, że wykrywanie samogłoski się przyzna [i {co oczywiście nie jest właściwe.
  • Wiele zależności od semantyki K&R sprawia, że ​​jest to brzydkie, ale hej, to jest golf golfowy.

Rzeczy do zobaczenia:

  • Jestem (chwilowo) przed obydwoma rozwiązaniami w Pythonie, nawet jeśli śledzę perla.

  • Zdobądź mnóstwo okropnych rzeczy, które zrobiłem dla wykrywania samogłosek. Ma to sens, jeśli zapisujesz reprezentacje ASCII w formacie binarnym i czytasz komentarz w długiej wersji.


„Musiałem ręcznie zmienić formułę, aby uzyskać akceptowalne wyniki”. To może być zła forma.
Joe Z.

1
Teraz przynajmniej podążam za wskazówkami Strigoidesa i dokonałem korekt na podstawie tego, kto rozumie tekst, a nie poprawkę czysto ad hoc, aby uzgodnić trzy przypadki testowe.
dmckee --- były moderator kociak

2

Python, 202 194 188 184 171 167 znaków

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

Najpierw uzyskaj całkowitą liczbę słów, dzieląc wzdłuż spacji i znaków nowej linii:

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

Następnie formuła. Liczby zdań i sylab są używane tylko raz, więc są osadzone w tym wyrażeniu.

Zdania to po prostu podział wejściowy wraz .z odfiltrowanymi znakami nowej linii:

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

Sylaby składają się z wejścia podzielonego wzdłuż non-samogłosek, z usuniętymi spacjami. To wydaje się konsekwentnie nieco zawyżać liczbę sylab, więc musimy go zmniejszyć (wydaje się, że robi to około .98):

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

202 -> 194: len(x)-2 zamiast len(x[1:-1]). Usunięto niepotrzebne wsporniki. Uczyniono sylabę wyrażeń regularnych bez rozróżniania wielkości liter

194 -> 188: Plik był wcześniej zapisywany jako dos, a nie w formacie uniksowym, co spowodowało, że wc -cnowe znaki były liczone jako dwa znaki. Ups

188 -> 184: Pozbądź się tych paskudnych x for x in ... if x!=..., przechowując wynik pośredni i odejmującx.count(...)

184 -> 171: Usuń wejście / wyjście i przekonwertuj na funkcję

171 -> 167: Wstaw len(x)-x.count(...)s do wzoru


Twoja odpowiedź nie musi zawierać procedur wejścia i wyjścia.
Joe Z.

@JoeZeng Oh, dobrze. Zamienię to w funkcję.
Strigoides,

1

Python 380 znaków

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

Jest to dość długie rozwiązanie, ale działa wystarczająco dobrze, przynajmniej pod warunkiem, że 3 testy.

Kod testowy

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

Wynik -

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

Użyłem stąd licznika sylab - Liczenie sylab

Bardziej czytelna wersja jest dostępna tutaj


1
if len(w)>2 and w[-1]=='e'and w[-2]not in v and w[-3]in v:c-= 1Prosty, ale dobre przybliżenie. Lubię to.
dmckee --- były moderator kociak

0

JavaScript, 191 bajtów

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)

Pierwszy przypadek testowy daje 112,9 (poprawna odpowiedź to 111,4, wyłączono o 1,5 punktu)

Drugi przypadek testowy daje 67,4 (poprawna odpowiedź to 65,1, wyłączono o 2,3 punktu)

Trzeci przypadek testowy daje 1,7 (poprawna odpowiedź to 3,7, wyłączone o 2,0 punkty)

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.