Объединив несколько подходов, я достиг следующего решения:
Код: Выделить всё
const combiningMarks = {
771: 126, // tilde
769: 180, // acute accent
768: 96, // grave accent
803: 196, //dot below Ä (placeholder letter, not relevant)
777: 214, //question mark Ö (placeholder letter, not relevant)
795: 220, //horn Ü (placeholder letter, not relevant)
770: 223, //circumflex ß (placeholder letter, not relevant)
774: 222 //Breve Þ (placeholder letter, not relevant)
}
// const target = 'mè bố bẳ người bệ bế bể bễ bề ';
const target = "a á ạ à ả ã ă ắ ặ ằ ẳ ẵ â ấ ậ ầ ẩ ẫ e é ẹ è ẻ ẽ ê ế ệ ề ể ễ i í ị ì ỉ ĩ o ó ọ ò ỏ õ ô ố ộ ồ ổ ỗ ơ ớ ợ ờ ở ỡ u ú ụ ù ủ ũ ư ứ ự ừ ử ữ y ý ỵ ỳ ỷ ỹ đ"
const decomposedString = target.normalize("NFD")
const codepoints = [...decomposedString].map(c => c.codePointAt(0))
const charsWithFullMarks = codepoints.map(c => combiningMarks[c] || c)
var finalString = String.fromCodePoint(...charsWithFullMarks)
finalString = finalString.replaceAll("Ü", '̛');
finalString = finalString.replaceAll("ß", '̂');
finalString = finalString.replaceAll("Þ", '̆');
finalString = finalString.replaceAll("´", '́');
finalString = finalString.replaceAll("`", '̀');
finalString = finalString.replaceAll("~", '̃');
finalString = finalString.replaceAll("Ä", '̣');
finalString = finalString.replaceAll("Ö", '̉');
document.getElementById("exp").innerHTML = finalStringКод: Выделить всё
:root,
html,
body {
font-family: sans-serif;
/* This needs to be different from the diacritic font for the coloring to work */
}
span.diacritical-mark-generic {
color: initial;
font-family: "DejaVu Sans";
/* font with the most accurate positioning */
}
span.diacritical-mark-red {
color: #ff3131;
font-family: "DejaVu Sans";
/* font with the most accurate positioning */
}
span.diacritical-mark-green {
color: #31ff61;
font-family: "DejaVu Sans";
/* font with the most accurate positioning */
}
span.diacritical-mark-blue {
color: #4081e9;
font-family: "DejaVu Sans";
/* font with the most accurate positioning */
}
span.diacritical-mark-pink {
color: #ff31cf;
font-family: "DejaVu Sans";
/* font with the most accurate positioning */
}
span.diacritical-mark-orange {
color: #ff9f04;
font-family: "DejaVu Sans";
/* font with the most accurate positioning */
}Код: Выделить всё
a á ạ à ả ã ă ắ ặ ằ ẳ ẵ â ấ ậ ầ ẩ ẫ e é ẹ è ẻ ẽ ê ế ệ ề ể ễ i í ị ì ỉ ĩ o ó ọ ò ỏ õ ô ố ộ ồ ổ ỗ ơ ớ ợ ờ ở ỡ u ú ụ ù ủ ũ ư ứ ự ừ ử ữ y ý ỵ ỳ ỷ ỹ đ
Этот код отделяет диакритические знаки от входных букв и добавляет их в качестве токенов-заполнителей после гласной, после чего заполнители преобразуются в комбинированные диакритические знаки и заключаются в диапазон для стилизации.
Мне кажется, это довольно хакерское решение с оговорками, например, что для того, чтобы использовать интервал, необходимо применить другой шрифт стиль вообще, а также выравнивание диакритических знаков, случайное или неудачное (вероятно, потому, что мы отключили ударение от буквы, используя другой диапазон и шрифт). В частности, неприемлемы особые случаи, такие как перекрытие сложенных циркумфлексов и тильды или отсутствие замены точки i соответствующими диакритическими знаками.
Я действительно не хочу писать целую систему рендеринга шрифтов с векторами и ручным позиционированием диакритических знаков, поэтому я ищу умный и простой способ преодолеть эти недостатки и раскрасить диакритические знаки, которые могут состоять из нескольких стопок, в определенные цвета.
Мобильная версия