¿Cuántos caracteres por personaje?

15

En http://shakespeare.mit.edu/ puede encontrar el texto completo de cada una de las obras de Shakespeare en una página (por ejemplo, Hamlet ).

Escriba un script que tome la url de una obra de stdin, como http://shakespeare.mit.edu/hamlet/full.html , y muestre la cantidad de caracteres de texto con los que cada personaje de la obra habló stdout, ordenados según quién habló más.

Los títulos de obra / escena / acto obviamente no cuentan como diálogo, ni los nombres de los personajes. El texto en cursiva y el [texto entre corchetes] no son diálogos reales, no deben contarse. Se deben contar los espacios y otros signos de puntuación dentro del diálogo.

(El formato de las obras parece muy consistente, aunque no las he mirado todas. Dime si he pasado por alto algo. Tu guión no tiene que funcionar para los poemas).

Ejemplo

Aquí hay una sección simulada de Much Ado About Nothing para mostrar lo que espero para la salida:

Más ruido sobre nada

Escena 0.

Mensajero

Voy a.

BEATRICE

Hacer.

LEONATO

Usted nunca.

BEATRICE

No.

Rendimiento esperado:

LEONATO 15
Messenger 7
BEATRICE 6

Puntuación

Este es el código de golf. El programa más pequeño en bytes ganará.

Pasatiempos de Calvin
fuente
8
¿Qué pasa si alguien hizo este desafío de Shakespeare en Shakespeare? Sería increíble si eso fuera posible ...
fuandon
¿Podemos suponer que tenemos una lista de los personajes de la obra? ¿O debemos inferir los caracteres del texto? Esto último es muy difícil dado que algunos caracteres (por ejemplo, Messenger) tienen una combinación de letras mayúsculas y minúsculas. Otros tienen nombres con solo letras mayúsculas (por ejemplo, LEONATO); y algunos de esos son nombres compuestos.
DavidC
Sí, debes inferir los nombres. Están formateados de manera muy diferente al diálogo, por lo que dado el html que los diferencia no debería ser demasiado complicado.
Calvin's Hobbies
1
¿Debería 'Todos' considerarse como un personaje separado?
es1024
1
@ es1024 Sí. Cualquier personaje de juego con un título único se considera separado, incluso si el resultado no tiene exactamente sentido.
Aficiones de Calvin

Respuestas:

4

PHP (240 caracteres)

Divide el html en cadenas (usando como delimitador), luego ejecuta un par de expresiones regulares para extraer el nombre y las palabras pronunciadas. Guarda la longitud de las palabras pronunciadas en una matriz. Golfizado:

<?@$p=preg_match_all;foreach(explode('/bl',implode(file(trim(fgets(STDIN)))))as$c)if($p('/=s.*?b>(.*?):?</',$c,$m)){$p('/=\d.*?>(.*?)</',$c,$o);foreach($m[1]as$n)@$q[$n]+=strlen(implode($o[1]));}arsort($q);foreach($q as$n=>$c)echo"$n $c\n";

Sin golf:

<?php
$html = implode(file(trim(fgets(STDIN))));
$arr = explode('/bl',$html);
foreach($arr as $chunk){
    if(preg_match_all('/=s.*?b>(.*?):?</',$chunk,$matches)){
        $name = $matches[1];
        preg_match_all('/=\d.*?>(.*?)</',$chunk,$matches);
        foreach($name as $n)
            @$names[$n] += strlen(implode($matches[1]));
    }
}
arsort($names);
foreach($names as $name=>$count)
    echo "$name $count\n";

Nota: Esto considera que 'Todos' es un personaje separado.

Ejemplo:

$php shakespeare.php <<< "http://shakespeare.mit.edu/hamlet/full.html"
HAMLET 60063
KING CLAUDIUS 21461
LORD POLONIUS 13877
HORATIO 10605
LAERTES 7519
OPHELIA 5916
QUEEN GERTRUDE 5554
First Clown 3701
ROSENCRANTZ 3635
Ghost 3619
MARCELLUS 2350
First Player 1980
OSRIC 1943
Player King 1849
GUILDENSTERN 1747
Player Queen 1220
BERNARDO 1153
Gentleman 978
PRINCE FORTINBRAS 971
VOLTIMAND 896
Second Clown 511
First Priest 499
Captain 400
Lord 338
REYNALDO 330
FRANCISCO 287
LUCIANUS 272
First Ambassador 230
First Sailor 187
Messenger 185
Prologue 94
All 94
Danes 75
Servant 49
CORNELIUS 45
es1024
fuente
1
Por favor, muestre algunos ejemplos de salida.
DavidC
@DavidCarraher Se ha agregado un ejemplo.
es1024
3

Rebol - 556 527

t: complement charset"<"d: charset"0123456789."m: map[]parse to-string read to-url input[any[(s: 0 a: copy[])some["<A NAME=speech"some d"><b>"copy n some t</b></a>(append a trim/with n":")some newline]<blockquote>newline any["<A NAME="some d">"copy q some t</a><br>newline(while[f: find q"["][q: remove/part f next find f"]"]s: s + length? trim head q)|<p><i>some t</i></p>newline][</blockquote>|</body>](foreach n a[m/:n: either none? m/:n[s][s + m/:n]])| skip]]foreach[x y]sort/reverse/skip/compare to-block m 2 2[print[x y]]

Es probable que esto se pueda jugar aún más, sin embargo, es poco probable que se encuentre por debajo de las respuestas ya proporcionadas :(

Sin golf:

t: complement charset "<"
d: charset "0123456789."
m: map []

parse to-string read to-url input [
    any [
        (s: 0 a: copy [])

        some [
            "<A NAME=speech" some d "><b>" copy n some t </b></a>
            (append a trim/with n ":")
            some newline
        ]

        <blockquote> newline
        any [
            "<A NAME=" some d ">" copy q some t </a><br> newline (
                while [f: find q "["] [
                    q: remove/part f next find f "]"
                ]
                s: s + length? trim head q
            )
            | <p><i> some t </i></p> newline
        ]
        [</blockquote> | </body>]
        (foreach n a [m/:n: either none? m/:n [s] [s + m/:n]])

        | skip
    ]
]

foreach [x y] sort/reverse/skip/compare to-block m 2 2 [print [x y]]

Este programa elimina [el texto entre corchetes] y también recorta el espacio en blanco que rodea el diálogo. Sin esto, la salida es idéntica a la respuesta es1024 .

Ejemplo:

$ rebol -q shakespeare.reb <<< "http://shakespeare.mit.edu/hamlet/full.html"
HAMLET 59796
KING CLAUDIUS 21343
LORD POLONIUS 13685
HORATIO 10495
LAERTES 7402
OPHELIA 5856
QUEEN GERTRUDE 5464
First Clown 3687
ROSENCRANTZ 3585
Ghost 3556
MARCELLUS 2259
First Player 1980
OSRIC 1925
Player King 1843
GUILDENSTERN 1719
Player Queen 1211
BERNARDO 1135
Gentleman 978
PRINCE FORTINBRAS 953
VOLTIMAND 896
Second Clown 511
First Priest 499
Captain 400
Lord 338
REYNALDO 312
FRANCISCO 287
LUCIANUS 269
First Ambassador 230
First Sailor 187
Messenger 185
Prologue 89
All 76
Danes 51
Servant 49
CORNELIUS 45
draegtun
fuente
0

Lisp común - 528

(use-package :plump)(lambda c(u &aux(h (make-hash-table))n r p)(traverse(parse(drakma:http-request u))(lambda(x &aux y)(case p(0(when(and n(not(ppcre:scan"speech"(attribute x"NAME"))))(setf r t y(#1=ppcre:regex-replace-all"aside: "(#1#"^(\\[[^]]*\\] |\\s*)"(text x)"")""))(dolist(w n)(incf(gethash w h 0)(length y)))))(1(if r(setf n()r()))(push(intern(text(aref(children x)0)))n)))):test(lambda(x)(and(element-p x)(setf p(position(tag-name x)'("A""b"):test #'string=)))))(format t"~{~a ~a~^~%~}"(alexandria:hash-table-plist h)))

Explicación

Esta es una versión ligeramente modificada que agrega información de impresión (ver pegar).

(defun c (u &aux
                 (h (make-hash-table)) ;; hash-table
                 n ;; last seen character name
                 r p
                 )
      (traverse                 ;; traverse the DOM generated by ...
       (parse                   ;; ... parsing the text string
        (drakma:http-request u) ;; ... resulting from http-request to link U
        )

       ;; call the function held in variable f for each traversed element
       (lambda (x &aux y)
         (case p
           (0 ;a
            (when(and n(not(alexandria:starts-with-subseq"speech"(attribute x "NAME"))))
              (setf r t)
              (setf y(#1=ppcre:regex-replace-all"aside: "(#1#"^(\\[[^]]*\\] |\\s*)"(text x)"")""))
              (format t "~A ~S~%" n y) ;; debugging
              (dolist(w n)
                (incf
                    (gethash w h 0) ;; get values in hash, with default value 0
                    (length y)))) ;; length of text
            )
           (1 ;b
            (if r(setf n()r()))
            (push (intern (text (aref (children x)0)))n))))

       ;; but only for elements that satisfy the test predicate
       :test
       (lambda(x)
         (and (element-p x) ;; must be an element node
              (setf p(position(tag-name x)'("A""b"):test #'string=)) ;; either <a> or <b>; save result of "position" in p
              )))

        ;; finally, iterate over the elements of the hash table, as a
        ;; plist, i.e. a list of alternating key values (k1 v1 k2 v2 ...),
        ;; and print them as requested. ~{ ~} is an iteration control format.
  (format t "~&~%~%TOTAL:~%~%~{~a ~a~^~%~}" (alexandria:hash-table-plist h)))

Notas

  • Elimino el texto entre corchetes, así como la aparición "a un lado:" que no está presente entre paréntesis (también recorto los espacios en blanco). Aquí hay un rastro de ejecución con el texto que coincide y el total de cada personaje, para Hamlet .

  • Como otras respuestas, Todo se supone que es un personaje. Podría ser tentador agregar el valor de todos a todos los demás personajes, pero esto sería incorrecto ya que "Todos" se refiere a los personajes realmente presentes en el escenario, lo que requiere mantener un contexto de quién está presente (seguimiento de "salida" "exeunt "y" ingresar "indicaciones). Ésto no está hecho.

volcado de memoria
fuente