Package: py-grammark
This is a python port of Grammark. The grammar checker developed by Mark Fullmer.
Visithttps://github.com/markfullmer/grammarkto learn more about Grammark.
All credit goes to markfullmer.The contributions of this work can be summarized as follows:Key words, that are used by the grammar rules are collected in JSON files. This makes it hopefully easier to manage expressions and the JSON files can be used in other projects.The grammar rules are defined in (informal) logic. It is presented in the next section of this README. This makes the workings of grammark more transparent. However, I reverse engineered those rules from the angular app and it is absolutely possible that I made mistakes.The different checks implemented by grammark, e.g., passive voice, wordiness, academic style..., are provided as functions in the Python package. The functions return the ratings, as proposed by grammark and offsets indicating the problematic positions.UsageInstall package with pip:pip install py-grammarkThen import the different functions:from grammark import check_wordiness, \
				check_nominalizations, \
				check_passive_voice, \
				check_sentences, \
				check_academic, \
				check_transitions, \
				check_grammar, \
				check_eggcorns

text = "This is some string."

check_wordiness(text)
check_normalizations(text)
...Every function can be called with the text as parameter. Text must be of type string.The return values look as follows:{
	"findings": [
		{"start_pos": 10, "end_pos": 12, "remark": "Some remark or None, if there is no"},
		...
	],
	"score": 40
}It returns a dictionary. The score is calculated as defined by Grammark (https://github.com/markfullmer/grammark).
The findings contain the offsets, where the found problem, resides in the provided text.The remarks are provided by Grammark. Again all credits goes tohttps://github.com/markfullmer/grammark.
The remark can beNoneif there are no remarks for a certain check.An (Informal) Definition of the Grammar RulesIn the following we define the workings of the different tools provided by grammark.Thereby, $W$ represents the set of words, that is built by parsing the text provided by the user (see sectionParsing the Textfor a detailed discussion).
Furthermore, $|w|$ represents the size of word $w \in W$ and we use $w[a:b]$ for $a,b \in \mathbb{N}$ to represent substrings, where $a,b$ represent positions in the string, where the substring starts and ends, respectively.
$pre(w) \in W$ indicates the predecessing word, that occurs before $w$ in the original text provided by the user.
We write $upper(w)$ for $w \in W$ to denote the word $w$ where the first letter is capitalized.Note that $w \in W$ represents not necessarily a single word, but can be also a sequence of words if we try to match several consecutive words.We use $s(w)$ to denote the sentence, that contains the word $w \in W$ and $s(w)[i]$ to select words in the sentence by index $i \in \mathbb{N}$.Passive voiceLet $I$ be the set of irregulars and $H$ be the set of helpers with sets as defined insrc/resources/passive_voice.json:The passive voice check hits, if for a word $w \in W$$(w[|w| - 1:|w|] = "ed" \lor w \in I) \land pre(w) \in H$In text: Every word that ends with "ed" or is an irregular verb and the predecessing word is a helper word.WordinessLet $K$ be the set of keywords. It is constructed by the first elements of the set keywords in filesrc/resources/wordiness.jsonThe wordiness check hits, if for a word $w \in W$$\forall k \in K: w = k \lor w = upper(k)$In text: We look if one of the elements in $K$ occurs in the text. We do this also for the situation, that it has a capitalized first letter.NominalizationsLet $E$ be the set of postfixes taken from the filesrc/resources/normalizations.jsonThe nominalization check hits if for a word $w \in W$$\exists a,b \in \mathbb{N}: w[a:b] \in E \land |w| > 7$In text: The rule checks if the word $w$ ends with a postfix contained in $E$ and if its length is greater than seven.SentencesLet $K$ be the set of keywords as defined in filesrc/resources/sentences.jsonThe sentences check hits if for a word $w \in W$$|s(w)| > 50 \lor s(w)[0] \in K$Here $|s(w)|$ denotes the number of words in the sentence.TransitionsLet $K$ be the set of keywords from the filesrc/resources/transitions.jsonThe transition check hits, if for a word $w \in W$$\forall k \in K: w = k \lor w = upper(k)$In text: We look if one of the elements in $K$ occurs in the text. We do this also for the situation, that it has a capitalized first letter.AcademicLet $K$ be the set of keywords from the filesrc/resources/academic.jsonThe academic check hits, if for a word $w \in W$$\forall k \in K: w = k \lor w = upper(k)$In text: We look if one of the elements in $K$ occurs in the text. We do this also for the situation, that it has a capitalized first letter.GrammarLet $K$ be the set of keywords from the filesrc/resources/grammar.jsonThe grammar check hits, if for a word $w \in W$$\forall k \in K: w = k \lor w = upper(k)$In text: We look if one of the elements in $K$ occurs in the text. We do this also for the situation, that it has a capitalized first letter.EgcornsLet $K$ be the set of keywords from the filesrc/resources/eggcorns.jsonThe grammar check hits, if for a word $w \in W$$\forall k \in K: w = k \lor w = upper(k)$In text: We look if one of the elements in $K$ occurs in the text. We do this also for the situation, that it has a capitalized first letter.Parsing the TextBasically, we use two variants to work with the text. Either we check word-wise, thereby,
the text is split based on the following chars " ,.!?:-\n'")({}". That means word are
limited by these chars and will be identified as single words.The other variant is based on regex in the hope that this is for certain operations more efficient.DevelopmentBuildpython3 -m buildRun testspython3 -m unittest tests.test_grammark.TestGrammark