feat: parse abbreviated counts like "59 млн" and "571 тыс."
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Sonnet 5.5
parent
39af9a3111
commit
edb450d4e6
@@ -0,0 +1,33 @@
|
||||
const UNITS = new Map([
|
||||
['k', 1e3], ['тыс', 1e3], ['тысяча', 1e3], ['тысячи', 1e3], ['тысяч', 1e3], ['thousand', 1e3],
|
||||
['m', 1e6], ['млн', 1e6], ['миллион', 1e6], ['миллиона', 1e6], ['миллионов', 1e6], ['million', 1e6],
|
||||
['b', 1e9], ['млрд', 1e9], ['миллиард', 1e9], ['миллиарда', 1e9], ['миллиардов', 1e9], ['billion', 1e9],
|
||||
]);
|
||||
|
||||
// "просмотров", "подписчиков", "views", "subscribers" and their other forms at the end of the text.
|
||||
const COUNT_WORDS = /\s*(просмотров|просмотра|просмотр|подписчиков|подписчика|подписчики|подписчик|views?|subscribers?)$/;
|
||||
const GROUPED_INTEGER = /^\d{1,3}(?:[ ,.]\d{3})+$/;
|
||||
const DECIMAL = /^\d+(?:[.,]\d+)?$/;
|
||||
|
||||
// Reads "59 млн", "571 тыс.", "1.2M", "12 345" and the like; the whole text must be a count.
|
||||
export function parseCount(text) {
|
||||
if (typeof text !== 'string') return null;
|
||||
const normalized = text.replace(/\s+/g, ' ').trim().toLowerCase().replace(COUNT_WORDS, '').trim();
|
||||
const match = /^(\d[\d ,.]*?)(?: ?([a-zа-яё]+)\.?)?$/.exec(normalized);
|
||||
if (!match) return null;
|
||||
const [, number, unit] = match;
|
||||
|
||||
if (unit === undefined) {
|
||||
if (/^\d+$/.test(number)) return Number(number);
|
||||
return GROUPED_INTEGER.test(number) ? Number(number.replace(/\D/g, '')) : null;
|
||||
}
|
||||
const multiplier = UNITS.get(unit);
|
||||
if (multiplier === undefined || !DECIMAL.test(number)) return null;
|
||||
return Math.round(Number(number.replace(',', '.')) * multiplier);
|
||||
}
|
||||
|
||||
export function parseViews(text) {
|
||||
if (typeof text !== 'string') return null;
|
||||
if (/^\s*(no|нет) (views|просмотров)\s*$/i.test(text)) return 0;
|
||||
return parseCount(text);
|
||||
}
|
||||
Reference in New Issue
Block a user