Wie viele Zeichen pro Zeichen?

15

Unter http://shakespeare.mit.edu/ finden Sie den vollständigen Text aller Stücke von Shakespeare auf einer Seite (z . B. Hamlet ).

Schreiben Sie ein Skript, das die URL eines Spiels von stdin aufnimmt, wie z. B. http://shakespeare.mit.edu/hamlet/full.html , und gibt die Anzahl der Textzeichen aus, die jedes Spielzeichen mit stdout gesprochen hat, sortiert nach wem sprach am meisten.

Die Spiel- / Szenen- / Act-Titel zählen offensichtlich nicht als Dialog, ebenso wenig wie die Charakternamen. Kursiver Text und [ Text in eckigen Klammern] sind keine eigentlichen Dialoge, sie sollten nicht gezählt werden. Leerzeichen und andere Satzzeichen im Dialog sollten gezählt werden.

(Das Format für die Stücke sieht sehr konsistent aus, obwohl ich nicht alle angeschaut habe. Sagen Sie mir, ob ich etwas übersehen habe. Ihr Skript muss für die Gedichte nicht funktionieren.)

Beispiel

Hier ist ein simulierter Abschnitt aus Viel Lärm um nichts , der zeigt, was ich für die Ausgabe erwarte:

Mehr Lärm um nichts

Szene 0.

Bote

Ich werde.

BEATRICE

Tun.

LEONATO

Du wirst nie.

BEATRICE

Nein.

Erwartete Ausgabe:

LEONATO 15
Messenger 7
BEATRICE 6

Wertung

Das ist Code Golf. Das kleinste Programm in Bytes gewinnt.

Calvins Hobbys
quelle
8
Was wäre, wenn jemand diese Shakespeare-Herausforderung in Shakespeare bestehen würde? Es wäre erstaunlich, wenn das überhaupt möglich wäre ...
fuandon
Können wir annehmen, dass wir eine Liste der Charaktere im Stück haben? Oder müssen wir die Zeichen aus dem Text ableiten? Letzteres ist sehr schwierig, da einige Zeichen (z. B. Messenger) aus Groß- und Kleinbuchstaben bestehen. Andere haben Namen mit nur Großbuchstaben (zB LEONATO); und einige davon sind zusammengesetzte Namen.
DavidC
Ja, Sie sollten die Namen entnehmen. Sie sind ganz anders formatiert als der Dialog, daher sollte es angesichts des HTML-Codes nicht allzu schwierig sein, sie zu unterscheiden.
Calvins Hobbys
1
Sollte "Alle" als separates Zeichen betrachtet werden?
Es1024
1
@ es1024 Ja. Jeder Spielcharakter mit einem eindeutigen Titel wird als getrennt betrachtet, auch wenn das Ergebnis nicht gerade sinnvoll ist.
Calvins Hobbys

Antworten:

4

PHP (240 Zeichen)

Unterteilt das HTML in Zeichenfolgen (als Begrenzungszeichen) und führt dann einige reguläre Ausdrücke aus, um den Namen und die gesprochenen Wörter zu extrahieren. Speichert die Länge der im Array gesprochenen Wörter. Golf gespielt:

<?@$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";

Ungolfed:

<?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";

Hinweis: Dies betrachtet "Alle" als ein separates Zeichen.

Beispiel:

$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
quelle
1
Bitte zeigen Sie einige Beispiele für die Ausgabe.
DavidC
@DavidCarraher Ein Beispiel wurde hinzugefügt.
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]]

Dies könnte wahrscheinlich weiter golfen werden, es ist jedoch unwahrscheinlich, dass die bereits gelieferten Antworten unterschritten werden :(

Ungolfed:

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]]

Dieses Programm entfernt [Text in eckigen Klammern] und schneidet auch umgebende Leerzeichen aus dem Dialogfeld. Ohne dies ist die Ausgabe identisch mit es1024 answer.

Beispiel:

$ 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
quelle
0

Common Lisp - 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)))

Erläuterung

Dies ist eine leicht modifizierte Version, die Druckinformationen hinzufügt (siehe Einfügen).

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

Anmerkungen

  • Ich entferne Text in eckigen Klammern sowie das "aside:" - Vorkommen, das nicht in eckigen Klammern steht (ich schneide auch Leerzeichen ab). Hier ist eine Ausführungsspur mit dem Text, der abgeglichen wird, und der Summe für jedes Zeichen für Hamlet .

  • Als andere Antwort wird angenommen, dass All ein Charakter ist. Es könnte verlockend sein, den Wert aller zu allen anderen Zeichen hinzuzufügen, aber dies wäre falsch, da "Alle" sich auf die tatsächlich auf der Bühne vorhandenen Zeichen bezieht, was erfordert, dass der Kontext der anwesenden Personen eingehalten wird (Verfolgung von "exit" -Exeunt "und" enter "). Das ist nicht fertig.

Core-Dump
quelle