Javascript-форум (https://javascript.ru/forum/)
-   Общие вопросы Javascript (https://javascript.ru/forum/misc/)
-   -   Причина неподдержки кириллицы в js-коде (https://javascript.ru/forum/misc/82994-prichina-nepodderzhki-kirillicy-v-js-kode.html)

hdma 23.08.2021 03:11

Причина неподдержки кириллицы в js-коде
 
Привет. Имеется большой сложный словарный скрипт, который делался для работы с латиницей — но при попытке добавить поддержку кириллицы, он не отрабатывает. То есть, когда по умолчанию юзер кликает на слово, набранное латиницей - задействуется приведенная ссылка, из которой апострофы и пробелы заменяются на URI-код:

Код:

<a href='?page=definition&word="+n.replace(/'/g,"%27").replace(/ /g,"%20")+"'>"+n+"</a>
Но если точно так же заменять кириллические буквы на код — почему-то код не срабатывает:

Код:

.replace(/а/g,"%430").replace(/о/g,"%43E")
Может кто знает: действительно ли проблема заключается в этой ссылке, и в ней нужно учесть какие-то особенности при работе с кириллицей — или дело в другом?

Aetae 23.08.2021 03:46

Используй на клиенте encodeURIComponent. На сервере соответствующий decode_uri для языка. Не надо делать своих нестандартных костылей.

hdma 23.08.2021 03:58

То есть, если таким образом заменять буквы — работать не будет, потому что нужен encodeURIComponent? Сам не смогу его добавить и потестировать, потому спрашиваю.

Aetae 23.08.2021 04:22

Может и будет. Всё заисит от кодировки сервера, кодировки js-файла и кодировки html файла. Самые разные сочетания могут породить самые разные варианты кодирования символов и самые разные глюки.
В современном вебе везде используется utf8. Но в utf8 символ "а" кодируется как "%D0%B0", а не как "%430".
encodeURIComponent обеспечивает стандартное кодирование безотносительно, но смысл имеет только если сервер раскодирует также по стандарту.

hdma 23.08.2021 05:09

А имеет значение, если это не сервер, а код приложения? То есть, это в приложении так реализовано, что через ссылку происходит переход к слову. Там тоже utf8, и замена с "%430" на "%D0%B0" изменений не дала.

hdma 23.08.2021 05:17

Интересно, что если перед кириллицей стоит один символ латиницы (например: "fслово") — то переход срабатывает.

Rise 23.08.2021 10:55

hdma,
Попробуй так:
<a href='?page=definition&word="+encodeURIComponent(n).replace(/'/g,"%27")+"'>"+n+"</a>

hdma 23.08.2021 12:32

Спасибо, теперь начал видеть кириллицу в начале списка, но по-прежнему не переходит. Кажется дело в том, что ниже есть другая строка, в которой символы кодируются в обратную сторону:

{a=a.replace(/%20/g," ").replace(/%430/g,"а").replace(/%43E/g,"о").replace(/%27/g,"'"),


Вообще говоря, речь о коде из этого приложения, с редким функционалом перехода по любым словам в тексте и поиска с подстановочными знаками, которые позволяют искать слова, правописание которых неизвестно. Там словарь на 200 тысяч слов очень экономно сделан. Если взглянете, тут по ссылке APK-файл, который можно открыть через любой архиватор — https://disk.yandex.ru/d/amhXyapjX_WA4Q, ну или установить на телефон.

Aetae 23.08.2021 13:30

decodeURIComponent чтоб раскодировать.)

hdma 23.08.2021 13:42

А как правильно записать это в строке? Так? —
{a=a.decodeURIComponent(n).replace(/%20/g," ").replace(/%27/g,"'"),

Rise 23.08.2021 14:14

hdma,
{a=decodeURIComponent(a),

hdma 23.08.2021 14:59

Что-то не идёт. Может потому что как-то надо кириллическую букву А (вместо английской A) правильно прописать для алфавита? —

case"A":return void a.e(5).then(a.bind(null,16)).then((function(i){var a=i.definitions_A

Rise 23.08.2021 15:00

hdma,
А что в русском алфавите только одна буква?

Зачем вообще там кириллица? Это же приложение, как я понял, не для перевода, а толковый словарь английского языка.

hdma 23.08.2021 15:08

Ну это для теста. В файле "app.js" я прописал кириллицей две буквы "аа" в самом начале списка слов. то же самое добавил в файле "3.js" в начале списка:
{"аа":0,

То есть, воспроизвел всё то же самое, как это работало для латиницы. Соответственно, мне кажется, если с первой буквой сработает, то и остальные пойдут. А так же, если перед этой кириллицей и тут — case"A":return — поставить англ. букву А, то переход по клику начинает работать.

hdma 23.08.2021 21:05

Цитата:

Сообщение от Rise (Сообщение 539659)
Зачем вообще там кириллица? Это же приложение, как я понял, не для перевода, а толковый словарь английского языка.

Дело в том, что я хотел попробовать такой же функционал для словаря на кириллице сделать.

Rise 24.08.2021 11:52

hdma,
Вот эти строки нужно менять как минимум:
// app.js

//1
"<a href='?page=definition&word="+n.replace(/'/g,"%27").replace(/ /g,"%20")+"'>"+n+"</a>"

//2
var N=["a",...,"-yl"],

//3
F={A:0,B:23288,C:45163,D:77117,E:98409,F:113516,G:129883,H:146789,I:161766,J:174946,K:178691,L:182759,M:195581,N:214319,
  O:223559,P:235471,Q:263522,R:265324,S:285095,T:324135,U:344471,V:355391,W:361599,X:371334,Y:371869,Z:373356,0:374863},

//4
W="ABCDEFGHIJKLMNOPQRSTUVWXYZ0",

//5
e.prototype.partitionIndexStart=function(e){var i=this.normalizeLetter(e);return F[i]},

//6
e.prototype.partitionIndexFinish=function(e){var i=this.normalizeLetter(e);return"Z"==i?F[0]:"0"==i?N.length:(i=String.fromCharCode(i.charCodeAt(0)+1),F[i])},

//7
case"A":return void a.e(5).then(a.bind(null,16)).then((function(i){var a=i.definitions_A;e.partitions.A=a,s(a)}));
case"B":return void a.e(6).then(a.bind(null,17)).then((function(i){var a=i.definitions_B;e.partitions.B=a,s(a)}));
...

//8
e.prototype.normalizeLetter=function(e){var i=e[0].toUpperCase();return i>="A"&&i<="Z"?i:"0"},

//9
a=a.replace(/%20/g," ").replace(/%27/g,"'"),

//10
se.navigate("?page=definition&word="+a),

//11 (регулярки)
/^[a-zA-Z0-9 '-]*$/
/[\.\d]|[A-Z]|-$|^-/
/\W/g
new RegExp("(\\W)"+i+"[\\.):]","ig");


// 5.js, 6.js, ...

//12
.push([[5],{16:function(a,o,t){"use strict";t.r(o),t.d(o,"definitions_A",
.push([[6],{17:function(a,o,n){"use strict";n.r(o),n.d(o,"definitions_B",
...

№1 и №9 сделано, №10 так:
se.navigate("?page=definition&word="+encodeURIComponent(a)),

№2 это база словаря, ее можно убрать пока из файла, чтобы не мешала, так как она занимает 95%, также можно убрать весь код до записи ,,,,,,,,,,,,,,,,function(e,i,a), так как он стандартный и не относится к логике приложения.

Каждый файл 5.js, 6.js и тд, относится к определенной букве и содержит определения, поэтому №7 и №12 должны соответствовать друг другу.

№5 менять не надо, просто показан для partitionIndexFinish.

Дальше думаю разберешься.

hdma 24.08.2021 14:10

Rise, вот спасибо, уважаемый! Буду пробовать

hdma 24.08.2021 15:42

Rise, если позволите, возникли вопросы. Я хотел бы сразу наладить возможность перехода к определению для первого слова с кириллицей, прописанного в базе — а дальше уже логику понял. Поэтому поначалу пытаюсь поменять только то, что запустит работу переходов по перечню слов. Для этого в самое начало базы добавил две буквы "а" кириллицей:

var N=["аа",


(И соответственно, в файл "3.js" добавил var a={"аа":0,)

И то же самое в №№ 3 и 4 (наши буквы "А", вместо английских):

//3
F={A:0,B:23288,C:45163,D:77117 ...
//4
W="ABCDEFGHIJKLMNOPQRSTUVWXYZ0",
//7
case"А":return void a.e(5).then(a.bind(null ...
//8
e.prototype.normalizeLetter=function(e){var i=e[0].toUpperCase();return i>="А"&&i<="Z"?i:"0"},


Во все регулярки во всём файле "app.js", в которых встречались "a-z" — добавил соответствующие регистрам диапазоны с кириллицей, А-Яа-яЁё —
/^[А-Яа-яЁёa-zA-Z0-9 '-]*$/
/[\.\d]|[А-ЯЁA-Z]|-$|^-/


Для "\W" — который означает "не-буква" — затрудняюсь найти соответствующую замену. Правильно ли понимаю, что в js при использовании шаблона \W — кириллица не опознаётся как буква, и именно поэтому ее следует изменить? И это же касается \W во второй строке, где есть экранирование? —

/\W/g
new RegExp("(\\W)"+i+"[\\.):]","ig");


В остальном — №1, №9, №10 — поменял и выяснилось, что переходить по первому слову с уже сделанными изменениями, не получается. Хотелось бы именно задействовать работу первого слова в базе, а в остальном я понял логику.

Rise 24.08.2021 21:11

Цитата:

Сообщение от hdma
\W — кириллица не опознаётся как буква

Да, \W это тоже самое что [^A-Za-z0-9_]. Character classes.
Цитата:

Сообщение от hdma
не получается.

partitionIndexFinish у тебя вернет undefined, потому что F['Б'] не определено, а значит циклы где эта функция используется не отработают.

hdma 24.08.2021 21:58

Цитата:

Сообщение от Rise (Сообщение 539713)
partitionIndexFinish у тебя вернет undefined, потому что F['Б'] не определено

А если я пока что не прописывал полный алфавит с кириллицей, а лишь поменял первую букву английского алфавита на первую букву русского — в этом случае требуется указывать «Б» как ты показал? То есть, ниже везде где встречается «А» — это кириллическая А, а остальной алфавит — это англ. буквы:
//3
F={A:0,B:23288,C:45163,D:77117 ...
//4
W="ABCDEFGHIJKLMNOPQRSTUVWXYZ0",
//7
case"А":return void a.e(5).then(a.bind(null ...
//8
e.prototype.normalizeLetter=function(e){var i=e[0].toUpperCase();return i>="А"&&i<="Z"?i:"0"},

Просто хотелось бы запустить переход по клику с минимумом изменений, так как если всё править - наверняка можно ошибиться и тогда сложнее будет понять, где был недочёт.

И затрудняюсь понять как прописывать экранированную \W. Попробовал по такому же принципу экранировать [^A-Za-z0-9_], — но тоже не пошло:
s=new RegExp("(\\W)"+i+"

заменил на:

s=new RegExp("(\[\^A-Za-z0-9_\])"+i+"

hdma 24.08.2021 22:10

Кстати, должны ли файлы «app.js» и «3.js» быть в UTF-8, или они по умолчанию в ANSI могут быть?

Rise 24.08.2021 23:14

Цитата:

Сообщение от hdma
требуется указывать «Б» как ты показал?

F={А:0,Б:23288,C:45163,D:77117 ...

Цитата:

Сообщение от hdma
но тоже не пошло

/\W/g так:
/[^А-Яа-яЁёA-Za-z0-9_]/g или /[^А-ЯЁA-Z0-9_]/ig или /[^А-ЯЁ\w]/ig

new RegExp("(\\W)"+i+"[\\.):]","ig") так:
new RegExp("([^А-ЯЁA-Z0-9_])"+i+"[\\.):]","ig") или new RegExp("([^А-ЯЁ\\w])"+i+"[\\.):]","ig")

Цитата:

Сообщение от hdma
быть в UTF-8

Да.

hdma 25.08.2021 00:40

Rise, зафурычило, спасибище!

Мне бы хотелось ещё один момент попробовать решить с вашей помощью — в отношении сохранения ударений в словах, которые бы при наборе не мешали поиску. Наверняка вы знаете такой символ ударения, который когда ставишь перед буквой — она делается ударной:
Акце́нт

Вот тут пример поиска как бы сквозь это ударение — то есть, при наборе букв ударение не мешает поиску. Возможно ли то же самое осуществить в разбираемом здесь коде — например, удалив этот символ ударения именно для поиска, но чтобы он оставался видимым на экране?

Rise 25.08.2021 07:02

Цитата:

Сообщение от hdma
символ ударения, который когда ставишь перед буквой

После буквы.
Цитата:

Сообщение от hdma
поиска как бы сквозь это ударение

Можно прокси сделать и удалять символ при чтении массива:
var N = ['aáa','cćc'];
N = new Proxy(N,{get(o,p){return(o.hasOwnProperty(p)&&p!='length')?o[p].replace('\u0301',''):o[p]}});
console.log(N[0], N[1], N[2], N.length);


Еще, не забыть, так как в Юникоде буква Ё находится вне диапазона А-Я , то надо немного переделать №6 и №8, т.е. если №4 будет выглядеть так, то:
//4
W="АБВГДЕЁЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯ0"
//6
e.prototype.partitionIndexFinish=function(e){var i=this.normalizeLetter(e);return"Я"==i?F[0]:"0"==i?N.length:(i=W[W.indexOf(i)+1],F[i])}
//8
e.prototype.normalizeLetter=function(e){var i=e[0].toUpperCase();return i>="А"&&i<="Я"||i=='Ё'?i:"0"}

hdma 25.08.2021 08:24

Круто, спасибо! Только не удаётся правильно вписать строку с прокси. Пробовал вот так сразу после массива, а также ниже вписывать, через запятые и через точку запятой —

"-ways","-yl"],N = new Proxy(N,{get(o,p){return(o.hasOwnProperty(p)&&p!=' length')?o[p].replace('\u0301',''):o[p]}});console.log(N[0], N[1], N[2], N.length),F={А:0,Б:23288,

Rise 25.08.2021 08:36

hdma,
А это ;console.log(...) зачем?

hdma 25.08.2021 12:36

Rise,
Точно, консоль лишняя) Попробовал, но акцент не отображается — похоже, что replace('\u0301','') везде его затирает.

hdma 25.08.2021 12:38

Вот так записал:

,"-ways","-yl"],N = new Proxy(N,{get(o,p){return(o.hasOwnProperty(p)&&p!=' length')?o[p].replace('\u0301',''):o[p]}}),F={А:0,Б:23288,C:45163,

Rise 25.08.2021 18:43

Цитата:

Сообщение от hdma
везде его затирает.

Да, так я неправильно сделал. Надо все места смотреть, где используется N, и решать в каждом конкретном случае надо делать sanitize или нет:
function sanitize(s){return s.replace('\u0301','')}

Просто так в этом моменте помочь не могу, так как это довольно трудозатратно.

hdma 25.08.2021 19:45

Rise, я позже насчет этого обращусь, спасибо большое. Возник такой вопрос: возможно ли в этом приложении включить работу тегов, чтобы в файлах с определениями ими можно было обрамлять элементы и они соответственно отображались? Хотя бы курсив?

Rise 27.08.2021 06:53

Цитата:

Сообщение от hdma
включить работу тегов

HTML-тегов?

hdma 27.08.2021 17:33

Да, мне бы хотелось возможности обрамлять текст тегами, как минимум курсив и жирность. То есть, чтобы можно было обернуть какой-либо текст из файла с определениями в теги, либо другими условными знаками, и он бы отображался в HTML формате. Например, прописывать так

Код:

{305315} <i>{300056} {203886}</i> of the {007980}
или так:

Код:

{305315} <<{300056} {203886}>> of the {007980}
Вот фрагмент кода из "app.js", который делает похожее в отношении других случаев, обрамляя некоторые участки определений в теги, отчего мне показалось возможным делать такое же для самостоятельно задаваемых знаков:

if(a.endsWith("..."))z=a;else{z="",e=function(e,i,a){for(var s=/{(\d\d\d\d\d\d)}/g,r=i.split("\n"),n="",o=e+": ",t=0;t<r.length;t++){var l=r[t].split("|");if(!(l.length<4)){var c=l[0];n+="<b class='theme-accent-colour'>(<i>"+c+".</i>)</b> ",o+="("+c+".) ";var u=l[1];u.length>0&&(n+="["+u+"] ");for(var d=3;d<l.length;d++)l.length>4&&(n+="<b class='theme-accent-colour'>"+(d-2).toString()+".</b> ",o+=" "+(d-2).toString()+". "),n+=l[d]+"&nbsp;&nbsp;",o+=l[d]+" ";var p=l[2];p.length>0&&(n+=" <span class='etym'>["+p+"]</span>"),n+="<br /><br />"}}return[n=n.replace(s,(function(i,s){var r=parseInt(s),n=a.getWord(r);return n===e?n:"<a href='?page=definition&word="+encodeURIComponent(n).replace(/ /g,"%20").replace(/'/g,"%27")+"'>"+n+"</a>"})),

Rise 27.08.2021 20:11

hdma,
Там же есть CSS, можно поменять, слова то и так в тегах.

hdma 27.08.2021 20:47

Rise,
Точно, спасибо. Они прямо в определениях поддерживаются. Видимо, в прошлый раз неправильно тестировал


Часовой пояс GMT +3, время: 16:07.