Count spelling errors in text; minimize the number of spelling errors in your code Write a program or function that takes two inputs:


A text message
The dictionary of English language, as it appears in this Github file (containing about 60000 words)


and outputs the number of spelling errors in the message (see below for definition and test cases).

You can receive the dictionary as a parameter to your function, as a pre-defined file that your program expects to find, as hard-coded data in your code, or in any other sensible manner.



Your code should itself look like a text message, with a minimal number of spelling errors. So, you will calculate the score of your code by feeding it to itself as input.

The winner is code that has the lowest score (minimal possible score is 0). If there are several answers with the same score, the winner is decided by code size (in characters). If two answers are still tied, the winner is the earlier one.



If required, you can assume the input message to be ASCII (bytes 32...126) with newlines encoded in a conventional manner (1 byte "10" or 2 bytes "13 10"), and non-empty. However, if your code has non-ASCII characters, it should also support non-ASCII input (so it can calculate its own score).

Characters are subdivided into the following classes:


Letters a...z and A...Z
Whitespace (defined here as either the space character or the newline character)
Punctuation . , ; : ! ?


Sentence-ending . ! ?

Garbage (all the rest)


A word is defined as a sequence of letters, which is maximal (i.e. neither preceded nor followed by a letter).

A sentence is defined as a maximal sequence of characters that are not sentence-ending.

A character is a spelling error if it violates any of the spelling rules:


A letter must belong to a dictionary word (or, in other words: each word of length N that doesn't appear in the dictionary counts as N spelling errors)
The first character in a sentence, ignoring any initial whitespace characters, must be an uppercase letter
All letters must be lowercase, except those specified by the previous rule
A punctuation character is only allowed after a letter or garbage
A newline character is only allowed after a sentence-ending character
Whitespace characters are not allowed in the beginning of the message and after whitespace characters
There should be no garbage (or, in other words: each garbage character counts is a spelling error)


In addition, the last sentence must be either empty or consist of exactly one newline character (i.e. the message should end with a sentence-ending character and an optional newline - let's call it rule 8).

Test cases (below each character is a rule that it violates; after =&gt; is the required answer):

Here is my 1st test case!!
           711           4                =&gt; 4

main(){puts("Hello World!");}
2   777    883     3     77 78            =&gt; 12

  This message starts with two spaces
66                                   8    =&gt; 3

What ? No apostrophe's??
     4              71 4                  =&gt; 4

  Extra   whitespace   is   BAD!
66      661111111111 66   66333           =&gt; 21

Several
lines?
Must be used only to separate sentences.
                                          =&gt; 1 (first linebreak is en error: rule 5)

"Come here," he said.
73         7                              =&gt; 3 (sentence starts with '"', not 'C')
Perl 6, 134 spelling errors



my token punctuation {&lt;[.,;:!?]&gt;}
my \text = slurp; my \mistakes=[]; for split /\.|\!|\?/, text { for .trim.match: :g, /&lt;:letter&gt;+/ -&gt; \word { (append mistakes, .comb when none words slurp pi given lc word) or (push mistakes, $_ if ((.from or word.from) xor m/&lt;[a..z]&gt;/) for word.match: :g, /./) }}
append mistakes, comb / &lt;after \s | &lt;punctuation&gt;&gt; &lt;punctuation&gt; | &lt;!before &lt;punctuation&gt; | &lt;:letter&gt; | \s&gt; . | &lt;!after \.|\!|\?&gt; \n | [&lt;before ^&gt; | &lt;after \s&gt;] \s /, text; say mistakes.Numeric


With extra whitespace for readability:

my token punctuation {&lt;[.,;:!?]&gt;}
my \text = slurp;
my \mistakes=[];
for split /\.|\!|\?/, text {
    for .trim.match: :g, /&lt;:letter&gt;+/ -&gt; \word {
        (append mistakes, .comb when none words slurp pi given lc word)
        or
        (push mistakes, $_ if ((.from or word.from) xor m/&lt;[a..z]&gt;/) for word.match: :g, /./)
    }
}
append mistakes, comb /
  &lt;after \s | &lt;punctuation&gt;&gt; &lt;punctuation&gt;
  | &lt;!before &lt;punctuation&gt; | &lt;:letter&gt; | \s&gt; .
  | &lt;!after \.|\!|\?&gt; \n
  | [&lt;before ^&gt; | &lt;after \s&gt;] \s
/, text;
say mistakes.Numeric


Notes:


Expects the dictionary in a file called 3.14159265358979 in the current working directory.
The only inspired part is the line
append mistakes, .comb when none words slurp pi given lc word,
the rest is pretty bad. But maybe it can at least serve as a baseline for better solutions... :)