Търсачката на един магазин не намира „Поръчка“, въпреки че думата е на страницата. Ключ в превод се подрежда на грешно място. Проверката на правописа подчертава дума, която изглежда безупречно. Във всеки от тези случаи думата не е това, което изглежда: една от буквите ѝ е латинска. В българския има шест малки букви, които се рисуват точно като латинските (а, е, о, р, с, у, а в повечето шрифтове и х и к), и всеки, който превключва между българска и английска подредба на клавиатурата, рано или късно вкарва латинско „o“ в кирилска дума. Оттам копирането я разнася. Същите текстове обикновено носят и "прави" кавички, дефис на мястото на тире и „3км“ без интервал. Тук показваме как да намерите смесените думи с една команда, как да ги поправите с код и кои кавички, тирета и дефиси иска българският текст. JavaScript е пуснат на Node 22, а командата с GNU grep, точно както са отпечатани.
#Защо една скрита буква е важна
За компютъра „Пoръчка“ с латинско o (U+006F) и „Поръчка“ с кирилско о (U+043E) са различни думи. Търсенето, подреждането, проверката на правописа, пренасянето и екранните четци работят с буквите, а не с формата им, затова смесената дума не се намира, подрежда се на странни места, подчертава се и може да бъде прочетена буква по буква. Unicode има име за такива букви, confusables (лесни за объркване), а докладите му за сигурност описват думите със смесени писмености като предупредителен знак, защото същият номер се ползва, за да изглежда фалшив домейн като истински. В обикновения текст това обикновено е просто грешка на клавиатурата, но струва също толкова: продукт, който никой не намира през търсачката на сайта, е продукт, който никой не купува.
Случва се и обратното. „Mаil“ с кирилско а в английски бутон изглежда правилно и се проваля по същия начин.
#Как да намерите смесените думи с една команда
Дума, която съдържа и двете писмености, почти никога не е правилна, затова се търси лесно. Режимът Perl на GNU grep познава писменостите на Unicode:
grep -rnoP '[\p{L}]*(\p{Cyrillic}\p{L}*\p{Latin}|\p{Latin}\p{L}*\p{Cyrillic})[\p{L}]*' lang
Върху езиков файл на Laravel с две нарочно вкарани грешки командата отпечата lang/bg/shop.php:4:Пoръчка и lang/bg/shop.php:5:Mаil и не докосна правилния ред. Пуснете я върху преводите, статиите в Markdown и шаблоните си; в голям сайт първото пускане рядко не намира нищо. Ако grep се оплаче от локала, задайте първо UTF-8, например с LC_ALL=C.UTF-8 пред командата.
#Как да ги поправите с код
Поправката е думата да се сложи в една писменост. Коя писменост, решава просто гласуване: печели писмеността с повече букви в думата, а се разменят само букви, които имат двойник в другата писменост. Буква без двойник, като латинско i в българска дума, има нужда от човек.
// Latin letters that look like Cyrillic ones, and back.
const TO_CYR = { a: "а", c: "с", e: "е", o: "о", p: "р", x: "х", y: "у", k: "к",
A: "А", B: "В", C: "С", E: "Е", H: "Н", K: "К", M: "М", O: "О", P: "Р", T: "Т", X: "Х", Y: "У" };
const TO_LAT = Object.fromEntries(Object.entries(TO_CYR).map(([l, c]) => [c, l]));
const CYR = /\p{Script=Cyrillic}/u;
const LAT = /\p{Script=Latin}/u;
export function fixWord(word) {
const chars = [...word];
const cyr = chars.filter((c) => CYR.test(c)).length;
const lat = chars.filter((c) => LAT.test(c)).length;
if (!cyr || !lat) return word; // one script: nothing to do
const map = cyr >= lat ? TO_CYR : TO_LAT; // the majority decides
const fixed = chars.map((c) => map[c] ?? c).join("");
return [...fixed].some((c) => CYR.test(c)) && [...fixed].some((c) => LAT.test(c)) ? null : fixed;
}
export function fixText(text) {
return text
.replace(/[\p{L}\p{M}]+/gu, (w) => fixWord(w) ?? w)
.replace(/"([^"\n]*\p{Script=Cyrillic}[^"\n]*)"/gu, (_, quoted) => `„${quoted}“`);
}
for (const s of ["Пoръчка № 1024", "Mаil адрес", "Пиши ни на \"Контакти\"", "Пoртфолиo"]) {
const word = s.split(" ")[0];
console.log(JSON.stringify(s), "=>", JSON.stringify(fixText(s)),
[...word].map((c) => c.codePointAt(0).toString(16).padStart(4, "0")).join(" "));
}
Кодът превръща „Пoръчка № 1024“ в „Поръчка № 1024“ и показва виновника в кодовете на първата дума: 041f 006f 0440, латинско 006f между две кирилски букви. „Mаil адрес“ става „Mail адрес“, защото думата има три латински букви и една кирилска. „Пoртфолиo“ с две латински букви се поправя наведнъж, а правите кавички около „Контакти“ стават „Контакти“. Когато fixWord() върне null, думата не може да се поправи с размяна и трябва да влезе в списък, който човек да прегледа.
Пускайте такава поправка върху текст, а не върху код: променлива или CSS клас с кирилска буква е отделна грешка, а поправката е на мястото, където текстът е написан, не само в изхода.
#Кавички, тирета и дефиси
- Кавички. Българският текст иска „…“: долна отваряща кавичка (U+201E) и горна затваряща (U+201C), което дават и данните на Unicode CLDR за български. И "правите" кавички, и английските “извити” изглеждат чужди в български текст. « » се срещат в някои печатни книги; изберете един стил и го спазвайте.
- Тирето между думи. Тире, което разделя части от изречението, се пише с интервал от двете страни: „Цената е важна – от нея зависи всичко.“ Дефис с интервали около него („важна - от нея“) е съкращение при писане, а не тире.
- Дефисът в думите. Сравнителната и превъзходната степен на прилагателните и наречията се пишат с малко тире и без интервали: по-добър, най-важното, по-бързо. Съветът на Института за български език добавя и другата половина на правилото: при съществителни, глаголи и някои изрази „по“ и „най“ се пишат разделно, а „по“ получава ударение, както в „пò ми се иска“. Затова „по - добър“ с интервали е развален дефис и правилната поправка е „по-добър“, а не тире.
- Числа и мерни единици. Между числото и мерната единица или съкращението има интервал: 2026 г., 3 км, 15 ч. Непрекъсваем интервал ги държи на един ред.
- Препинателни знаци. Без интервал преди запетая, точка, двоеточие или въпросителен знак, един интервал след тях и многоточие (…) вместо три точки, ако стилът ви го ползва.
#Какво да оставите на мира
Автоматичните поправки имат нужда от граници. Интервалите от числа като 10-20, датите, телефонните номера и кодовете на продукти запазват дефисите си. Кавичките в програмния код са синтаксис, а екранираното \" в низ трябва да остане както е. Ключовете в езиков файл, адресите, CSS класовете и HTML атрибутите, които никой не чете, са код, докато alt, title, placeholder и aria-label са текст, който хората четат и слушат. Ред, пълен с ы и э, вероятно е на руски нарочно; едно ы в български ред е грешка на клавиатурата.
#Разширение за редактора, което прави това, докато пишете
Направихме Kavichka, разширение за Visual Studio Code за български текст в Markdown, езикови файлове, Blade, Vue, JSON и обикновен текст. То подчертава латински букви, скрити в кирилски думи, и обратното, случайни руски или украински букви, прави кавички, дефис на мястото на тире, липсващи интервали пред мерни единици, интервал пред запетая и още, предлага бърза поправка за всеки случай и поправя цял файл с една стъпка за отмяна. В кода гледа само в низовете и коментарите, в шаблоните само текста и атрибутите, които хората четат, а интервалите от числа оставя на мира. Освен това транслитерира от кирилица на латиница и прави адреси (slug). Тествано е с автоматични тестове и в VS Code 1.141 под Linux. Следва и правилото по-горе за „по“ и „най“: „по - добър“ и „най - важното“ стават „по-добър“ и „най-важното“, с дефис и без интервали, а не с тире. Разширението е обявено като „Очаквайте скоро“.
#Често задавани въпроси
Защо търсачката на сайта не намира дума, която е на страницата?
Често защото една буква от думата на страницата е латинска. Изглежда същата, но е друг знак, затова думата не съвпада с това, което хората пишат. Потърсете в източника думи със смесени писмености.
Какви кавички се пишат на български?
„…“, с отваряща кавичка долу и затваряща горе. Това са кавичките, които данните на Unicode CLDR дават за български, и тези, които ползват повечето български сайтове и издатели.
По-добър или по добър?
По-добър, с малко тире и без интервали, както при всяка сравнителна и превъзходна степен на прилагателно или наречие. „По“ и „най“ се пишат разделно, с ударение върху „по“, само пред съществителни, глаголи и в някои изрази.
Защо VS Code рисува рамки около кирилски букви?
VS Code отбелязва знаци, които могат да се объркат с други, като кирилските е и о в низове в кода. Това е друга, по-широка проверка; настройката editor.unicodeHighlight.ambiguousCharacters я изключва, ако инструмент, който съобщава само истински смесени думи, върши работата.
Коментари
Коментари
Все още няма коментари. Задайте въпрос или споделете какво проработи при вас.
Оставете коментар