cjk_index 1.1.0 → 1.1.1
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/CHANGELOG.md +10 -0
- data/README.md +6 -4
- data/lib/cjk_index/normalizer.rb +13 -5
- data/lib/cjk_index/runtime.js +10 -0
- data/lib/cjk_index/searcher.rb +6 -2
- data/lib/cjk_index/version.rb +1 -1
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 615a0f6d44d6e04e21f66aeb15778e39adf566ec078f11c69ceecf41473e1388
|
|
4
|
+
data.tar.gz: 7a106a769e2cc57e382727c8ada1afbba691fbdb7620c0f487eddbe31610abf8
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 2783f62f61930fbd740261d552d7b8092b098b1e15a4fe28741b37f766b9670f5e66045c994da3bcff2b16644f28772b681b8f6fd70b28440f8dd58571e0759e
|
|
7
|
+
data.tar.gz: c1faf175e55309bf62568d7215bee743fe7a4f0942d9621e1ad8f846e9082393dd51c38ef2ef141bdada33ce887a253d4ae533e812abe6e07cf59423901e3638
|
data/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,15 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 1.1.1 (2026-10-28)
|
|
4
|
+
|
|
5
|
+
- Variation selectors (U+FE00–U+FE0F and the ideographic U+E0100–U+E01EF)
|
|
6
|
+
are dropped when folding: 「珊」 followed by an ideographic variation
|
|
7
|
+
selector is 「珊」. Before, the selector broke a CJK run in two, so
|
|
8
|
+
「珊瑚」 did not find 「珊\u{E0100}瑚」, and a table file of your own with
|
|
9
|
+
such a cell was rejected as "not one character". `highlight` and
|
|
10
|
+
`excerpt` keep the selector inside the mark with its character. Rebuild
|
|
11
|
+
indexes whose text has variation selectors.
|
|
12
|
+
|
|
3
13
|
## 1.1.0 (2026-10-28)
|
|
4
14
|
|
|
5
15
|
- `variants` also takes table files of your own: one group per line,
|
data/README.md
CHANGED
|
@@ -24,8 +24,8 @@ even when it is an exact title. cjk_index instead:
|
|
|
24
24
|
stores their positions, so a query matches only where its bigrams are
|
|
25
25
|
adjacent and in order: an exact substring match, with no dictionary or
|
|
26
26
|
native extension (the same idea as [kensaku](https://github.com/whispcat/kensaku));
|
|
27
|
-
- folds variants on both sides: NFKC, lowercase,
|
|
28
|
-
old-form kanji → modern form (「圖」→「図」), 々 expanded (「佐々木」→「佐佐木」),
|
|
27
|
+
- folds variants on both sides: NFKC, lowercase, variation selectors
|
|
28
|
+
dropped, katakana → hiragana, old-form kanji → modern form (「圖」→「図」), 々 expanded (「佐々木」→「佐佐木」),
|
|
29
29
|
and optionally Traditional ↔ Simplified Chinese (from OpenCC) and old
|
|
30
30
|
Hangul in the Private Use Area;
|
|
31
31
|
- ranks with BM25 per field, with field boosts;
|
|
@@ -386,8 +386,10 @@ cjk_index:
|
|
|
386
386
|
variants: [ja, _data/itaiji.tsv]
|
|
387
387
|
```
|
|
388
388
|
|
|
389
|
-
Each cell is folded first (NFKC, lowercase,
|
|
390
|
-
|
|
389
|
+
Each cell is folded first (NFKC, lowercase, variation selectors dropped,
|
|
390
|
+
katakana → hiragana), so a cell written as an ideographic variation sequence
|
|
391
|
+
(珊 + U+E0100) is the character itself, and the table listed first still
|
|
392
|
+
picks the form a group folds to. The index records
|
|
391
393
|
the entry as written (`_data/itaiji.tsv`), not the full path, and its digest
|
|
392
394
|
covers the file's contents, so editing the file means rebuilding the index.
|
|
393
395
|
To read such an index from another folder in Ruby, pass the normalizer:
|
data/lib/cjk_index/normalizer.rb
CHANGED
|
@@ -5,9 +5,10 @@ require "json"
|
|
|
5
5
|
|
|
6
6
|
module CJKIndex
|
|
7
7
|
# Folds text so that spelling variants a reader treats as "the same" compare
|
|
8
|
-
# equal: NFKC (full-width -> half-width etc.), lowercase,
|
|
9
|
-
#
|
|
10
|
-
#
|
|
8
|
+
# equal: NFKC (full-width -> half-width etc.), lowercase, variation
|
|
9
|
+
# selectors dropped (珊 followed by an ideographic variation selector is 珊),
|
|
10
|
+
# katakana -> hiragana, character variants from the selected tables, and
|
|
11
|
+
# the iteration mark 々 expanded to the preceding character.
|
|
11
12
|
#
|
|
12
13
|
# The same rules run in the browser (see Runtime), so an index built here
|
|
13
14
|
# and a query typed there are folded identically.
|
|
@@ -52,6 +53,11 @@ module CJKIndex
|
|
|
52
53
|
KATAKANA_LAST = 0x30F6
|
|
53
54
|
KANA_OFFSET = 0x60
|
|
54
55
|
ITERATION_MARK = "々"
|
|
56
|
+
# Variation selectors (VS1-VS16 and the ideographic VS17-VS256) only pick
|
|
57
|
+
# a glyph of the character before them: 珊 with or without U+E0100 is the
|
|
58
|
+
# same character to a reader, so they are dropped, not kept as a run of
|
|
59
|
+
# their own between two CJK characters. In String#delete form.
|
|
60
|
+
VARIATION_SELECTORS = "\u{FE00}-\u{FE0F}\u{E0100}-\u{E01EF}"
|
|
55
61
|
|
|
56
62
|
def self.default
|
|
57
63
|
@default ||= new
|
|
@@ -121,14 +127,16 @@ module CJKIndex
|
|
|
121
127
|
"#{tables.inspect} (an older cjk_index?); rebuild it"
|
|
122
128
|
end
|
|
123
129
|
|
|
124
|
-
# Character by character:
|
|
125
|
-
# then 々 to the (folded) character
|
|
130
|
+
# Character by character: variation selectors dropped, katakana to
|
|
131
|
+
# hiragana, then the variant tables, then 々 to the (folded) character
|
|
132
|
+
# before it. Done as passes over the
|
|
126
133
|
# whole string, which gives the same result as one loop over the
|
|
127
134
|
# characters (the loop in runtime.js) and is several times faster in Ruby.
|
|
128
135
|
def normalize(text)
|
|
129
136
|
return "" if text.nil?
|
|
130
137
|
|
|
131
138
|
s = text.to_s.unicode_normalize(:nfkc).downcase
|
|
139
|
+
s = s.delete(VARIATION_SELECTORS)
|
|
132
140
|
s = s.tr(KATAKANA, HIRAGANA)
|
|
133
141
|
# 々 repeats the folded character before it, which may be several
|
|
134
142
|
# characters (ko): fold one character at a time, as runtime.js does
|
data/lib/cjk_index/runtime.js
CHANGED
|
@@ -59,6 +59,10 @@
|
|
|
59
59
|
// Score multiplier for matches found by prefix or typo expansion.
|
|
60
60
|
var EXPANDED = 0.6;
|
|
61
61
|
|
|
62
|
+
// Variation selectors (VS1-VS16, VS17-VS256): dropped, as
|
|
63
|
+
// CJKIndex::Normalizer::VARIATION_SELECTORS in Ruby.
|
|
64
|
+
var SELECTOR = /^[\ufe00-\ufe0f\u{e0100}-\u{e01ef}]$/u;
|
|
65
|
+
|
|
62
66
|
// Folds one character; prev is the previous folded character (for 々).
|
|
63
67
|
function foldChar(ch, prev) {
|
|
64
68
|
var c = ch.codePointAt(0);
|
|
@@ -73,6 +77,7 @@
|
|
|
73
77
|
var out = '';
|
|
74
78
|
var prev = null;
|
|
75
79
|
for (var ch of String(text).normalize('NFKC').toLowerCase()) {
|
|
80
|
+
if (SELECTOR.test(ch)) continue;
|
|
76
81
|
prev = foldChar(ch, prev);
|
|
77
82
|
out += prev;
|
|
78
83
|
}
|
|
@@ -534,11 +539,16 @@
|
|
|
534
539
|
// Each folded code point remembers which original characters it came
|
|
535
540
|
// from. A character may fold to several (ko: one Private Use Area
|
|
536
541
|
// character -> a jamo sequence), and a cluster may compose into fewer.
|
|
542
|
+
// A character that folds to nothing (a variation selector) belongs to
|
|
543
|
+
// the one before it: a match on 珊 marks its selector too.
|
|
537
544
|
function emit(str, from, to) {
|
|
545
|
+
var before = norm.length;
|
|
538
546
|
for (var c of str.normalize('NFKC').toLowerCase()) {
|
|
547
|
+
if (SELECTOR.test(c)) continue;
|
|
539
548
|
prev = foldChar(c, prev);
|
|
540
549
|
for (var p of prev) { norm.push(p); start.push(from); end.push(to); }
|
|
541
550
|
}
|
|
551
|
+
if (norm.length === before && end.length) end[end.length - 1] = to;
|
|
542
552
|
}
|
|
543
553
|
for (var i = 0, j; i < chars.length; i = j) {
|
|
544
554
|
for (j = i + 1; j < chars.length && JOINS_PREVIOUS.test(chars[j]); j++);
|
data/lib/cjk_index/searcher.rb
CHANGED
|
@@ -353,19 +353,23 @@ module CJKIndex
|
|
|
353
353
|
chars = text.to_s.chars
|
|
354
354
|
norm = +""
|
|
355
355
|
origin = []
|
|
356
|
+
ends = []
|
|
356
357
|
chars.each_with_index do |ch, i|
|
|
357
358
|
folded = normalizer.normalize(ch)
|
|
358
359
|
# 々 depends on the previous character, so fold it in context.
|
|
359
360
|
folded = norm[-1] if folded == Normalizer::ITERATION_MARK && !norm.empty?
|
|
361
|
+
# A character that folds to nothing (a variation selector) belongs to
|
|
362
|
+
# the one before it: a match on 珊 marks its selector too.
|
|
363
|
+
ends[-1] = i + 1 if folded.empty? && !ends.empty?
|
|
360
364
|
norm << folded
|
|
361
|
-
folded.length.times { origin << i }
|
|
365
|
+
folded.length.times { origin << i; ends << i + 1 }
|
|
362
366
|
end
|
|
363
367
|
needles = normalizer.normalize(query).split(Tokenizer::SEPARATOR).reject(&:empty?)
|
|
364
368
|
ranges = needles.flat_map do |needle|
|
|
365
369
|
found = []
|
|
366
370
|
from = 0
|
|
367
371
|
while (at = norm.index(needle, from))
|
|
368
|
-
found << [origin[at],
|
|
372
|
+
found << [origin[at], ends[at + needle.length - 1]]
|
|
369
373
|
from = at + needle.length
|
|
370
374
|
end
|
|
371
375
|
found
|
data/lib/cjk_index/version.rb
CHANGED