///|
/// franc only looks at this many UTF-16 code units of the input.
let max_sample_length : Int32 = 2048
///|
fn in_ranges(ranges : FixedArray[Int32], cp : Int32) -> Bool {
let mut lo = 0
let mut hi = ranges.length() / 2 - 1
while lo <= hi {
let mid = (lo + hi) / 2
if cp < ranges[mid * 2] {
hi = mid - 1
} else if cp > ranges[mid * 2 + 1] {
lo = mid + 1
} else {
return true
}
}
false
}
///|
/// Code points below this get their scripts from `script_masks` instead of
/// a search in every script's ranges: it covers the alphabetic scripts and
/// leaves Han, kana and Hangul to the search.
let mask_limit : Int32 = 0x3100
///|
/// For each code point below `mask_limit`, a bit per script of
/// `script_ranges` that contains it.
let script_masks : FixedArray[Int32] = FixedArray::makei(mask_limit, cp => {
let mut mask = 0
for s in 0.. FixedArray[Int32] {
let counts = FixedArray::make(script_ranges.length(), 0)
let limit = if text.length() < max_sample_length {
text.length()
} else {
max_sample_length
}
let mut i = 0
while i < limit {
let unit = text.unsafe_get(i).to_int()
let mut cp = -1
if unit >= 0xD800 && unit <= 0xDBFF && i + 1 < limit {
let next = text.unsafe_get(i + 1).to_int()
if next >= 0xDC00 && next <= 0xDFFF {
cp = 0x10000 + ((unit - 0xD800) << 10) + (next - 0xDC00)
i += 1
}
} else if unit < 0xD800 || unit > 0xDFFF {
cp = unit
}
i += 1
if cp < 0 {
continue
}
if cp < mask_limit {
let mask = script_masks[cp]
if mask != 0 {
for s in 0.. (Int32, Int32) {
let counts = script_counts(text)
let mut best = -1
let mut best_count = 0
for s in 0.. best_count {
best = s
best_count = counts[s]
}
}
(best, best_count)
}
///|
/// The writing system used by most characters of `text`, following
/// franc-min 6.2.0: only the first 2048 UTF-16 code units are examined,
/// and ties go to the script listed first in `Script::all()`. Returns
/// `None` when no character belongs to a supported script, e.g. for empty
/// input, digits, punctuation or emoji.
///
/// A character can belong to more than one script: Han ideographs count
/// for both `Han` and `Kana`, so Chinese text is `Han` (the tie goes to
/// `Han`) while Japanese text mixing kana and kanji is `Kana`.
pub fn detect_script(text : String) -> Script? {
match top_script(text) {
(-1, _) => None
(index, _) => Some(all_scripts[index])
}
}