vicary 0.2.16 → 0.2.18
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/assets/MANIFEST.json +4 -4
- data/assets/stop_words_never_capitalised.txt +15 -13
- data/lib/vicary/candidates.rb +90 -6
- data/lib/vicary/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 96894f65cf1e88e86b89131843ae808215e94c6df4ce8e62b47286fd8ba60431
|
|
4
|
+
data.tar.gz: 3054de303e6ba58b370a27d34d96b046ba27878f2bcbe8e40efa0c421c09f1b3
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 80246adb714cb8a2d32794187fafdd80cc58b573bf633cf5f6c89528f89cc71624e1bba013eea26f6b0c7fdf238f8d7e033b25391b60fd7338c7439ad8e823fd
|
|
7
|
+
data.tar.gz: 9c1b2a572734f144b49cc770be0d731f4b3559d88d020b9a6be77d78c9dd24faa1a25219a5a1274e46c1e3697c87c569e36d7b9228acd84769e24fcb1faed1ce
|
data/assets/MANIFEST.json
CHANGED
|
@@ -22,11 +22,11 @@
|
|
|
22
22
|
}
|
|
23
23
|
},
|
|
24
24
|
"stop_words_never_capitalised.txt": {
|
|
25
|
-
"bytes":
|
|
26
|
-
"entries":
|
|
25
|
+
"bytes": 8108,
|
|
26
|
+
"entries": 511,
|
|
27
27
|
"format": 1,
|
|
28
28
|
"min_package_version": "0.2.10",
|
|
29
|
-
"sha256": "
|
|
29
|
+
"sha256": "809e92aa74f001533be8bd33bfe119f5edab4bef2fbde687140f16c998c1039f"
|
|
30
30
|
},
|
|
31
31
|
"stop_words_sometimes_capitalised.txt": {
|
|
32
32
|
"bytes": 6351,
|
|
@@ -37,5 +37,5 @@
|
|
|
37
37
|
}
|
|
38
38
|
},
|
|
39
39
|
"manifest_version": 1,
|
|
40
|
-
"written_by": "vicary 0.2.
|
|
40
|
+
"written_by": "vicary 0.2.17"
|
|
41
41
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!lexicon 1
|
|
2
|
-
#!list stop_words_never_capitalised
|
|
2
|
+
#!list stop_words_never_capitalised 511
|
|
3
3
|
# Ordinary words that must never become name candidates, and that English never
|
|
4
4
|
# capitalises in the middle of a sentence.
|
|
5
5
|
#
|
|
@@ -58,6 +58,7 @@
|
|
|
58
58
|
a an the this that these those there here it its it's
|
|
59
59
|
i me my mine myself we us our ours ourselves you your yours
|
|
60
60
|
he him his she her hers they them their theirs who whom whose which what
|
|
61
|
+
how why where wherever whatever whoever
|
|
61
62
|
and or but so because although though however therefore thus hence yet
|
|
62
63
|
if then else when while until since before after during once whenever
|
|
63
64
|
for from to into onto out off over under above below between among across
|
|
@@ -109,18 +110,19 @@
|
|
|
109
110
|
cants coulds didnts dids doeses doings donts durings eithers elses etcs
|
|
110
111
|
everies everybodies everyones everythings everywheres feels fews finallies
|
|
111
112
|
finds froms gaves gets gives gos gots growings hads hases havings helpeds
|
|
112
|
-
hences hims hises howevers ids ifs ills ins insteads intos ises isnts
|
|
113
|
-
keeps kepts knews knows learneds learnings learns leaves lefts lets
|
|
114
|
-
lookings looks makes maybes mights mosts movings muches musts
|
|
115
|
-
neededs neithers nobodies nos nothings nots nowheres nows offs
|
|
116
|
-
onces onlies ons ontos ourselveses outs perhapses playings
|
|
117
|
-
quites rarelies rathers reads reallies remembereds remembers
|
|
118
|
-
saws says sets severals shalls shes shoulds sinces sittings
|
|
119
|
-
someones somethings sometimeses somewheres standings starteds
|
|
120
|
-
suches talkings taughts teaches tells thans thems thens therefores
|
|
121
|
-
theses thinkings thinks thises thoses thoughs thoughts throughs thuses
|
|
113
|
+
hences hims hises howevers hows ids ifs ills ins insteads intos ises isnts
|
|
114
|
+
justs keeps kepts knews knows learneds learnings learns leaves lefts lets
|
|
115
|
+
lookeds lookings looks makes maybes mights mosts movings muches musts
|
|
116
|
+
myselfs neededs neithers nobodies nos nothings nots nowheres nows offs
|
|
117
|
+
oftens okays onces onlies ons ontos ourselveses outs perhapses playings
|
|
118
|
+
pluses puts quites rarelies rathers reads reallies remembereds remembers
|
|
119
|
+
runnings saids saws says sets severals shalls shes shoulds sinces sittings
|
|
120
|
+
somebodies someones somethings sometimeses somewheres standings starteds
|
|
121
|
+
stoppeds suches talkings taughts teaches tells thans thems thens therefores
|
|
122
|
+
thes theses thinkings thinks thises thoses thoughs thoughts throughs thuses
|
|
122
123
|
todays togethers tolds tomorrows toos trieds tries tryings unders unlesses
|
|
123
124
|
untils ups uses usings usuallies veries versuses walkings wanteds wants
|
|
124
|
-
wases wents weres whenevers whens
|
|
125
|
-
|
|
125
|
+
wases wents weres whatevers whenevers whens wheres wherevers whethers
|
|
126
|
+
whiches whies whoevers whoms whos whoses withins withouts wonts workeds
|
|
127
|
+
woulds writes wrotes yeahs yeses yesterdays yets yous
|
|
126
128
|
# <<< end generated inflections
|
data/lib/vicary/candidates.rb
CHANGED
|
@@ -257,6 +257,16 @@ module Vicary
|
|
|
257
257
|
# Matches the abbreviation a break candidate sits directly behind.
|
|
258
258
|
TRAILING_WORD = /([A-Za-z]+)\.\s*\z/
|
|
259
259
|
|
|
260
|
+
# Words that name the letter after them as a letter: "a capital C", "a big M".
|
|
261
|
+
# Feedback on spelling and capitals says this all the time, and the letter
|
|
262
|
+
# then stood alone mid-sentence with nothing to tell it from an initial.
|
|
263
|
+
# Measured on 696 generated replies: 4 of the 39 placeholders a host's guard
|
|
264
|
+
# had to remove.
|
|
265
|
+
LETTER_NAMING_WORDS = Set.new(%w[capital big small lowercase uppercase letter]).freeze
|
|
266
|
+
|
|
267
|
+
# The word directly before a span, read back over whitespace and an opening quote.
|
|
268
|
+
PRECEDING_WORD = /([A-Za-z]+)[\s'"‘“]*\z/
|
|
269
|
+
|
|
260
270
|
# {SENTENCE_BREAK} with the `\A` arm removed, so it cannot match empty.
|
|
261
271
|
#
|
|
262
272
|
# A dialect difference, and it moved a number. `SENTENCE_BREAK` matches the
|
|
@@ -300,6 +310,39 @@ module Vicary
|
|
|
300
310
|
most much many few several enough
|
|
301
311
|
]).freeze
|
|
302
312
|
|
|
313
|
+
# Phonetic spellings of English stop words, each with the stop word it
|
|
314
|
+
# spells. Young writers, and young Spanish-L1 writers most of all,
|
|
315
|
+
# spell the closed-class words by ear — "dey sai ai smel", "so ai dont get
|
|
316
|
+
# mai clos dirtier" — and several of those spellings are given names the
|
|
317
|
+
# tier knows, so the lowercase route masked "sai ai" and "mai clos" and the
|
|
318
|
+
# sentence-initial rule let the tier vouch for "Ai", "Mi" and "De". A
|
|
319
|
+
# spelling of a stop word is the same word, so in a document that writes
|
|
320
|
+
# this way it is a stop word too. Only the spellings are read; the pairing
|
|
321
|
+
# is documentation. See `phonetic_function_words` for when a document
|
|
322
|
+
# qualifies.
|
|
323
|
+
PHONETIC_FUNCTION_WORDS = {
|
|
324
|
+
"ai" => "i", "becuz" => "because", "bicuz" => "because", "bot" => "but",
|
|
325
|
+
"cud" => "could", "da" => "the", "dan" => "than", "dat" => "that",
|
|
326
|
+
"de" => "the", "deir" => "their", "dem" => "them", "den" => "then",
|
|
327
|
+
"dere" => "there", "dese" => "these", "dey" => "they", "dis" => "this",
|
|
328
|
+
"dose" => "those", "frum" => "from", "hiz" => "his", "iz" => "is",
|
|
329
|
+
"mai" => "my", "mi" => "me", "sai" => "say", "sed" => "said",
|
|
330
|
+
"shud" => "should", "sum" => "some", "tu" => "to", "wat" => "what",
|
|
331
|
+
"wen" => "when", "wud" => "would", "wuz" => "was", "yu" => "you",
|
|
332
|
+
"yur" => "your",
|
|
333
|
+
}.freeze
|
|
334
|
+
|
|
335
|
+
# Distinct phonetic spellings a document must write in lower case before
|
|
336
|
+
# any of them is read as a word rather than a name. One is a coincidence —
|
|
337
|
+
# a friend called Mai — two different ones is a writer spelling by ear.
|
|
338
|
+
PHONETIC_REGISTER_MIN = 2
|
|
339
|
+
|
|
340
|
+
PHONETIC_TOKEN = Regexp.new(
|
|
341
|
+
"(?<![A-Za-z'’-])(?:" +
|
|
342
|
+
PHONETIC_FUNCTION_WORDS.keys.sort_by { |w| [-w.length, w] }.join("|") +
|
|
343
|
+
")(?![A-Za-z'’-])"
|
|
344
|
+
)
|
|
345
|
+
|
|
303
346
|
HONORIFIC_SET = Set.new(HONORIFICS.map(&:downcase)).freeze
|
|
304
347
|
|
|
305
348
|
# One capitalised word, hyphens and apostrophes included so
|
|
@@ -742,6 +785,20 @@ module Vicary
|
|
|
742
785
|
strip(without_clitic(strip(token.downcase, ".,")), "'’")
|
|
743
786
|
end
|
|
744
787
|
|
|
788
|
+
# The phonetic spellings this document uses as words, to be read as
|
|
789
|
+
# stops. Empty unless the document writes at least PHONETIC_REGISTER_MIN
|
|
790
|
+
# distinct spellings in lower case. When it does, the spellings it writes
|
|
791
|
+
# in lower case — the writer's own testimony that the token is a word to
|
|
792
|
+
# them — less any it also capitalises mid-sentence, which is the opposite
|
|
793
|
+
# testimony and wins.
|
|
794
|
+
def phonetic_function_words(text, written_as_a_capital = Set.new)
|
|
795
|
+
seen = Set.new
|
|
796
|
+
each_match(text, PHONETIC_TOKEN) { |m| seen << m[0] }
|
|
797
|
+
return Set.new if seen.size < PHONETIC_REGISTER_MIN
|
|
798
|
+
|
|
799
|
+
Set.new(seen.reject { |w| written_as_a_capital.include?(w) })
|
|
800
|
+
end
|
|
801
|
+
|
|
745
802
|
# Whether a capital on `token` mid-sentence is a mistake rather than a
|
|
746
803
|
# construction — the narrow half of the stoplist.
|
|
747
804
|
#
|
|
@@ -846,7 +903,11 @@ module Vicary
|
|
|
846
903
|
# the stoplist so that a bare "Mrs." cannot become a candidate on its own,
|
|
847
904
|
# but "Mrs. Okonkwo" has to stay whole: masking only the surname leaves the
|
|
848
905
|
# relationship and the surname's position in the text.
|
|
849
|
-
|
|
906
|
+
#
|
|
907
|
+
# `phonetic` is `phonetic_function_words` for the document: spellings read
|
|
908
|
+
# as stop words here. Except a particle *inside* a run — "Maria de Cruz"
|
|
909
|
+
# keeps its `de` however the rest of the document spells "the".
|
|
910
|
+
def trim(tokens, phonetic = Set.new)
|
|
850
911
|
runs = []
|
|
851
912
|
current = []
|
|
852
913
|
tokens.each_with_index do |token, index|
|
|
@@ -854,7 +915,10 @@ module Vicary
|
|
|
854
915
|
HONORIFIC_SET.include?(strip(token.downcase, ".,")) &&
|
|
855
916
|
index + 1 < tokens.length &&
|
|
856
917
|
!stop?(tokens[index + 1])
|
|
857
|
-
|
|
918
|
+
spelled_stop = !phonetic.empty? && phonetic.include?(fold(token)) &&
|
|
919
|
+
!(index.positive? && index < tokens.length - 1 &&
|
|
920
|
+
PARTICLES.include?(token))
|
|
921
|
+
if (stop?(token) || spelled_stop) && !introduces_a_name
|
|
858
922
|
unless current.empty?
|
|
859
923
|
runs << current
|
|
860
924
|
current = []
|
|
@@ -871,6 +935,18 @@ module Vicary
|
|
|
871
935
|
# Reading the document's own orthography
|
|
872
936
|
# ---------------------------------------------------------------------
|
|
873
937
|
|
|
938
|
+
# A lone capital that is a label or a letter, never an initial: glued to a
|
|
939
|
+
# digit (`E9`, a quote label the word pattern used to cut at the digit) or
|
|
940
|
+
# named as a letter by the word before it ({LETTER_NAMING_WORDS}). Only a
|
|
941
|
+
# single character is ever released; `Jake2009` stays a candidate.
|
|
942
|
+
def letter_not_a_name?(text, start, finish)
|
|
943
|
+
return false unless finish - start == 1
|
|
944
|
+
return true if finish < text.length && text[finish].match?(/[0-9]/)
|
|
945
|
+
|
|
946
|
+
preceding = PRECEDING_WORD.match(text[0...start])
|
|
947
|
+
!preceding.nil? && LETTER_NAMING_WORDS.include?(preceding[1].downcase)
|
|
948
|
+
end
|
|
949
|
+
|
|
874
950
|
# Offsets at which a sentence begins.
|
|
875
951
|
#
|
|
876
952
|
# A break directly behind a title abbreviation is not one — see
|
|
@@ -1849,7 +1925,7 @@ module Vicary
|
|
|
1849
1925
|
# capitalisation signal, and the seed stands on the given-name tier
|
|
1850
1926
|
# alone.
|
|
1851
1927
|
def find_lowercase_candidates(text, is_given, protected_span, corroborate = nil,
|
|
1852
|
-
settlement = nil)
|
|
1928
|
+
settlement = nil, phonetic = Set.new)
|
|
1853
1929
|
tokens = each_match(text, LOWER_TOKEN).map do |m|
|
|
1854
1930
|
[m[0], m.begin(0), m.begin(0) + m[0].length]
|
|
1855
1931
|
end
|
|
@@ -1857,7 +1933,10 @@ module Vicary
|
|
|
1857
1933
|
index = 0
|
|
1858
1934
|
while index < tokens.length
|
|
1859
1935
|
word, start, = tokens[index]
|
|
1860
|
-
|
|
1936
|
+
# A phonetic spelling may not SEED a span ("sai ai smel"), but may
|
|
1937
|
+
# still be the token a real seed reaches ("jeni sai") — see the
|
|
1938
|
+
# reference.
|
|
1939
|
+
if stop?(word) || phonetic.include?(word) || !is_given.call(word)
|
|
1861
1940
|
index += 1
|
|
1862
1941
|
next
|
|
1863
1942
|
end
|
|
@@ -1996,6 +2075,10 @@ module Vicary
|
|
|
1996
2075
|
)
|
|
1997
2076
|
written_as_a_capital = casing.written_as_a_capital
|
|
1998
2077
|
lower_cased = casing.written_in_lower_case
|
|
2078
|
+
# Read off the same casing pass, so a spelling the writer capitalises
|
|
2079
|
+
# mid-sentence is never one of them; and only where a given-name oracle
|
|
2080
|
+
# exists, because it only withdraws what the tier proposed or vouched for.
|
|
2081
|
+
phonetic = given_name.nil? ? Set.new : phonetic_function_words(text, written_as_a_capital)
|
|
1999
2082
|
stray_capitals = mid_sentence_corroboration && !given_name.nil? &&
|
|
2000
2083
|
capitalises_ordinary_words?(text, headings)
|
|
2001
2084
|
|
|
@@ -2007,7 +2090,7 @@ module Vicary
|
|
|
2007
2090
|
tokens = words(span)
|
|
2008
2091
|
# A long all-caps run means the capitalisation told us nothing, so the
|
|
2009
2092
|
# stoplist is carrying the whole decision.
|
|
2010
|
-
trim(tokens).each do |run|
|
|
2093
|
+
trim(tokens, phonetic).each do |run|
|
|
2011
2094
|
next if run.empty?
|
|
2012
2095
|
|
|
2013
2096
|
joined = run.join(" ")
|
|
@@ -2017,6 +2100,7 @@ module Vicary
|
|
|
2017
2100
|
|
|
2018
2101
|
start = m.begin(0) + offset
|
|
2019
2102
|
next if is_protected.call(start, start + joined.length)
|
|
2103
|
+
next if letter_not_a_name?(text, start, start + joined.length)
|
|
2020
2104
|
|
|
2021
2105
|
# Cheapest of the three capital-discounting rules and the only one
|
|
2022
2106
|
# that reads neither position nor list, so it goes first.
|
|
@@ -2078,7 +2162,7 @@ module Vicary
|
|
|
2078
2162
|
# evidence to offer and is better served by it.
|
|
2079
2163
|
find_lowercase_candidates(
|
|
2080
2164
|
text, given_name, is_protected,
|
|
2081
|
-
habit == LOWERCASE ? nil : written_as_a_capital, settlement
|
|
2165
|
+
habit == LOWERCASE ? nil : written_as_a_capital, settlement, phonetic
|
|
2082
2166
|
).each do |candidate|
|
|
2083
2167
|
next if claimed.any? { |s, e| candidate.start < e && candidate.end > s }
|
|
2084
2168
|
|
data/lib/vicary/version.rb
CHANGED
|
@@ -6,5 +6,5 @@ module Vicary
|
|
|
6
6
|
# Shared across all three front doors on purpose: one detector, one number. A
|
|
7
7
|
# gem 0.3.0 that corresponds to nothing on PyPI cannot be reasoned about, and
|
|
8
8
|
# the parity claim is between *versions*, not between package names.
|
|
9
|
-
VERSION = "0.2.
|
|
9
|
+
VERSION = "0.2.18"
|
|
10
10
|
end
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: vicary
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.2.
|
|
4
|
+
version: 0.2.18
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Blake Thomas
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2026-10-
|
|
11
|
+
date: 2026-10-22 00:00:00.000000000 Z
|
|
12
12
|
dependencies: []
|
|
13
13
|
description: |
|
|
14
14
|
Finds the names a student writes about — classmates, teachers, relatives — and
|