1

Тема: JScript: Определить юникодность имени файла - как?

Попытался из скрипта определить, является ли имя файла юникодным. Идей нет. Проблема в том, что имя файла - строка, а представление строк внутри скрипта не зависит от окружающей действительности. Русские имена файлов - вполне себе ансишные, но скрипт

var u=WScript.Arguments(0),v='';
for(var i=0;i<u.length;i++)v+=u.charCodeAt(i)+'\n';
WScript.echo(v);

выводит коды далеко за 255.

2

Re: JScript: Определить юникодность имени файла - как?

Serge Yolkin, это зависит исключительно от файловой системы.

3

Re: JScript: Определить юникодность имени файла - как?

Serge Yolkin, Видимо я не совсем в теме и что-то не понимаю. Что мешает ориентироваться по значению этих кодов ? Есть какой-нибудь пример с двумя именами - "юникодным" и "неюникодным" ?

Передумал переделывать мир. Пашет и так, ну и ладно. Сделаю лучше свой !

4

Re: JScript: Определить юникодность имени файла - как?

Например, файл с именем "Я" (без расширения) в скрипте даёт код 1071, а "нормальные программы" считают, что это имя в кодировке ANSI, состоящее из единственного символа с кодом 223. "По-настоящему" юникодные символы лежат в том же диапазоне, например, греческая альфа - 945

5

Re: JScript: Определить юникодность имени файла - как?

Понял. А на что это в дальнейшем сказывается и почему нельзя по кодам сделать условие проверки и дальнейшее решение о поведении кода ?

Передумал переделывать мир. Пашет и так, ну и ладно. Сделаю лучше свой !

6

Re: JScript: Определить юникодность имени файла - как?

А каким образом "нормальные программы" получают это имя? Если из своей командной строки, то кодировка зависит, например, от того, какую версию функции GetCommandLine они используют — A или W. Что используют, то и получат.

7

Re: JScript: Определить юникодность имени файла - как?

Проверил на VBScript


Option Explicit

Dim path, tmpStr, i

If WScript.arguments.count > 0 Then
    path = WScript.arguments(0)
    For i=1 to Len(path)
        tmpStr = tmpStr & Asc(mid(path,i,1)) & vbCrlf
    Next
End If

MsgBox tmpStr

Занятно. С параметром "Я" возвращает 223. А если использовать AscW вместо Asc, то возращает 1071, т.е расширенный юникодный вариант.

Передумал переделывать мир. Пашет и так, ну и ладно. Сделаю лучше свой !

8

Re: JScript: Определить юникодность имени файла - как?

Анализ кодов делать муторно - надо все возможные символы проверить (я, например, думал, что двойная угловая кавычка - это уже юникод, а оказалось - нет).
А в JS так изящно получить 223 вместо 1071 можно? Или это привелегия VBS?

9

Re: JScript: Определить юникодность имени файла - как?

alexii, от файловой системы зависимости не нашёл. И на exFAT32, и на NTFS результат одинаковый. Других под рукой нет.

10

Re: JScript: Определить юникодность имени файла - как?

Кстати, только сейчас обратил внимание: судя по кодам, это UTF-16BE, а я думал, в скриптах LE...

11

Re: JScript: Определить юникодность имени файла - как?

Правильно думали, в JScript и VBScript используется UTF-16 LE, как и в целом в Windows.

12

Re: JScript: Определить юникодность имени файла - как?

Serge Yolkin пишет:

А в JS так изящно получить 223 вместо 1071 можно? Или это привелегия VBS?

Возможно глупость ляпну, но...


var u=WScript.Arguments(0),v='';
for(var i=0;i<u.length;i++)v+=u.charCodeAt(i)-838+'\n';
WScript.echo(v);
Передумал переделывать мир. Пашет и так, ну и ладно. Сделаю лучше свой !

13 (изменено: Serge Yolkin, 2013-10-18 22:04:25)

Re: JScript: Определить юникодность имени файла - как?

Xameleon, э-э-э... я не совсем точно сформулировал цель. Так уменьшатся коды всех символов, включая действительно юникодные, а те что менее 838 и вовсе станут отрицательными...
А что возвращает Asc, если символ всё-таки юникодный (та же альфа, например)?

Ага! Asc возвращает код 63 - вопросительный знак. То, что нужно. Вот бы аналог в JS...


YMP, но "Я" имеет код 1071 в BE, или я что-то не понимаю?

14

Re: JScript: Определить юникодность имени файла - как?

alexii, от файловой системы зависимости не нашёл. И на exFAT32, и на NTFS результат одинаковый. Других под рукой нет.

FAT, она же FAT-12 и FAT-16. Поддержка Unicode'а была добавлена только начиная с NTFS и VFAT. Но, как я понимаю, Вас не это интересует, а имеют ли все символы имени файла представление в ANSI, либо же есть и символы, которые не могут быть преобразованы в ANSI.

Поскольку юникод корректно не отображается, то — здесь:
WScript.Echo "A", Asc("A"), AscB("A"), AscW("A") WScript.Echo "?", Asc("?") - Pastebin.com

15

Re: JScript: Определить юникодность имени файла - как?

Serge Yolkin пишет:

YMP, но "Я" имеет код 1071 в BE, или я что-то не понимаю?

LE и BE — это разные способы записи в память (или файл) одного и того же кода. У LE сначала пишется младший байт, а у BE — старший. Но код тот же самый.

16 (изменено: Serge Yolkin, 2013-10-19 08:34:08)

Re: JScript: Определить юникодность имени файла - как?

alexii пишет:

Вас не это интересует, а имеют ли все символы имени файла представление в ANSI, либо же есть и символы, которые не могут быть преобразованы в ANSI.

В общем, да. Винда (юникодовая), при записи имени объекта в файловую систему, преобразует символы, имеющие аналог в ANSI, как ANSI; не имеющие аналога - как UTF-16. На этом основаны некоторые "кулхацкерские" шуточки, не всегда смешные. Цель - найти имена файлов/папок, имеющие такие символы. Помимо прочего, несмотря на 21 век, не все программы корректно обрабатывают такие имена. То, что это просто, я уже понял, благодаря уважаемому Xameleon, но мой опыт на VBS - меньше недели. Вопрос: есть ли аналогичный, или ненамного более сложный способ на JS?

YMP, верю на слово (некоторые текстовые редакторы показывают разные коды символов для LE и BE).

17

Re: JScript: Определить юникодность имени файла - как?

Ещё на счёт Asc: правильно ли я понял, что эта команда преобразует полученный на входе символ, имеющий аналог в ANSI, кодом аналога, не имеющий - кодом 63 ? На входе-то всё равно юникод...

18

Re: JScript: Определить юникодность имени файла - как?

Serge Yolkin пишет:

Ещё на счёт Asc: правильно ли я понял, что эта команда преобразует полученный на входе символ, имеющий аналог в ANSI, кодом аналога, не имеющий - кодом 63 ? На входе-то всё равно юникод...

При перекодировке используются таблицы. Там не имеющим аналогов в ANSI-кодировке юникодным символам сопоставлен символ "?". Посмотрите, например, хекс-редактором файл system32\C_1251.NLS.

(некоторые текстовые редакторы показывают разные коды символов для LE и BE).

Видимо, читают BE как LE. Тогда число, конечно, другое получится. Можно трактовать это и как другой код, но, на мой взгляд, идеологически это неверно.

19

Re: JScript: Определить юникодность имени файла - как?

В общем, да. Винда (юникодовая), при записи имени объекта в файловую систему, преобразует символы, имеющие аналог в ANSI, как ANSI; не имеющие аналога - как UTF-16.

Не преобразует. Имена файлов всегда пишутся в Unicode. Исключение — создание короткого имени файла вида 8.3.

20 (изменено: Serge Yolkin, 2013-10-19 18:08:32)

Re: JScript: Определить юникодность имени файла - как?

alexii, и правда, не преобразует. Дамп тому свидетель... Просто первые 128 символов имеют те же коды, если не считать нулевой байт (в смысле, со значением 0x00). Был не прав.

И всё же, можно ли в js использовать виндовое преобразование, без написания собственного кода замены, как Asc в vbs?

21

Re: JScript: Определить юникодность имени файла - как?

И всё же, можно ли в js использовать виндовое преобразование, без написания собственного кода замены, как Asc в vbs?

Не могу сказать. Подождём ответа наших специалистов. В принципе, ведь можно использовать формат *.wsf. Не думали над этим?

22

Re: JScript: Определить юникодность имени файла - как?

alexii пишет:

В принципе, ведь можно использовать формат *.wsf. Не думали над этим?

Я даже дальше двинул: четвёртый день vbs изучаю. [censored/] Даже что-то получаться начало, но, Бог ты мой, [censored/] !!!

23

Re: JScript: Определить юникодность имени файла - как?

Если список файлов большой, то можно просто в первом случае запустить cmd с командой dir, а затем запустить cmd с параметром /u и dir, тогда сразу станет ясно, кто содержит юникодные символы, а кто нет.

24

Re: JScript: Определить юникодность имени файла - как?

JSman
Win 8.1 Preview : в обоих случаях вывод одинаковый, похоже, юникодовый.

25

Re: JScript: Определить юникодность имени файла - как?


var s="Привет:)";
WScript.Echo(/^[\u0001-\u0080а-я]*$/i.test(s).toString());

26

Re: JScript: Определить юникодность имени файла - как?

JSman
В принципе, да, но набор символов в регулярке надо несколько расширить.
Впрочем, в этой проблеме ещё несколько нюансов появилось: юникодовые имена по разному выдаются свойством name объекта файл (или папка), созданным fileSystemObject и Shell.Application (последний случай предпочтительнее), а с символами \x263A (смайлик) и \x263C (солнышко) ещё забавнее - в js они передаются нормально, а в vbs - заменяются на символы ANSI (0,O). В общем, требуется дополнительное изучение вопроса, т.к. победить с наскока не удалось.

27

Re: JScript: Определить юникодность имени файла - как?

И причем тут VBS?)
В примере я указал, что ANSI де факто символы 0-127 + Кирилица. Ну в общем чем мог, тем помог.

28 (изменено: Serge Yolkin, 2013-10-25 02:29:28)

Re: JScript: Определить юникодность имени файла - как?

JSman
Да про VBS - это к слову. Просто проблема оказалась несколько шире, чем я думал. И на счёт ANSI де факто не всё так просто. Например, имя "Ђ‡" ни разу не юникодовое...

Но всё равно спасибо.

29

Re: JScript: Определить юникодность имени файла - как?

JSman, в целом Вы были правы (особенно, на счет того, что VBS ни при чем). Остановился пока на таком варианте:

/[^а-яё\x01-\xFF]/i.test(e));

но не уверен в универсальности решения.

А VBS, который я тоже пытался использовать, заменяет некоторые чисто юникодные символы на неизвестно откуда взятые ANSI аналоги.

30

Re: JScript: Определить юникодность имени файла - как?

Да, и на счет "Ђ‡" я теперь не уверен. Кажется, это всё-таки юникод...

31

Re: JScript: Определить юникодность имени файла - как?

/[^а-яё\x01-\xFF]/i.test(e));

Диапазон до \xFF явно неверно задан. Вернее будет от От 0 до 127 с учетом кириллицы.

32 (изменено: Serge Yolkin, 2013-11-05 23:48:05)

Re: JScript: Определить юникодность имени файла - как?

JSman, похоже, Вы опять правы. Прошу прощения за упрямство. Изучение проблемы, о котором я писал в #26 показало, что юникодовым именем файла (в интернете) называется такое имя, при котором файл не открылся в какой-то программе у называющего. Это "определение" не позволяет задать единственный критерий, но Ваш, пожалуй, лучший. По крайней мере, строго корректный.

Кстати, диапазон, наверное, надо уменьшить до 126, а то символ 0x7F тоже какой-то не совсем ансишный... Или, всё же, допустимый?

33 (изменено: Serge Yolkin, 2013-11-07 01:27:40)

Re: JScript: Определить юникодность имени файла - как?

Провёл эксперимент на тему "что винда считает юникодом".
Отчет без претензий на полноту охвата.
Скачал 16 прграмм (в основном редакторы и утилиты) с заявленным отсутствием поддержки юникодных имен файлов.
Из них 7 прекрасно поддержали все тестовые пути/файлы (видимо, начиная с какой-то версии поддержка появилась).
Остальные, с незначительными отличиями*, продемонстрировали следующее поведение:
— все символы имени из одного диапазона:
1. все файлы с именами на латинице, любой (в пределах разумного) длины, с пробелами и без открываются нормально;
2. кириллица — то же самое;
3. латиница с диакритикой из второй половины западной (!) ANSI — то же самое**;
4. корявые символы из второй половины таблицы ANSI (Ђ,‡, «, », — …) — то же самое;
5. некоторые (не все) совсем уж юникодные символы, вроде "?"(смайлик) — (!!!) открываются, если нет пробелов, но (!) программа думает, что это совсем другие символы***;
— смешанные:
6. латиница + кириллица — прекрасно открываются;
7. латиница + латиница с диакритикой — то же самое**;
8. латиница + корявые символы из второй половины таблицы ANSI — то же самое;
9. кириллица + корявые символы из второй половины таблицы ANSI — (!) то же самое;
— не открываются:
10. греческие в любой комбинации, даже по одиночке — юникод;
11. кириллица + латиница с диакритикой — юникод (видимо, потому, что не могут быть в одной таблице ANSI любой кодовой страницы);
12. совсем уж юникодные символы из п.5 + любые другие, включая пробелы — юникод;
13. юникодные, которые "не все" из п.5, например "?"(солнышко)

*   Отличия, действительно, незначительные: степень корявости отображения имени в заголовке окна и подобные. Правда, одна программка (к сожалению, забыл как зовут) пробивалась через юникодные имена папок, но не могла открыть файл с юникодным именем, остальные и через папки не проходят.
**  С диакритикой вообще интересно: похоже, винде на неё чихать, по крайней мере, создать рядом файлы "O" и "?"(О с тильдой) нельзя...
*** Многие из таких символов заменяются на латинские буквы, но, если с диакритикой всё валидно — в папку "G?te"(2-я буква - u с умляутом) можно зайти как в "Gute", то в папку "?"(смайлик) как в "O" не зайдёшь.

Для желающих повторить эксперимент: наиболее стабильно и, при этом, типично работает GetDiz

Я понимаю, что такая загогулина ни в одном стандарте не описана, но постараюсь решить задачку в существующих реалиях.

34

Re: JScript: Определить юникодность имени файла - как?

Всё-таки Asc рулит. Видимо, использует тот же механизм замены символов, что и сама винда. А проверять коды не надо. Пусть этим винда и занимается, если такая умная:

// проверка имён файлов/папок на «неюникодность» (допустимость для старых программ)
// предполагается, что файлы и папки с тестовыми именами лежат в папке скрипта
var
 a=[],
 c=new ActiveXObject('MSScriptControl.ScriptControl'),
 f=new ActiveXObject('Scripting.FileSystemObject'),
 n=f.getFolder(f.getParentFolderName(WScript.scriptFullName));

c.language='VBScript';
c.allowUI=false;
c.addCode(
'Function FB(E)\n'+
'  FB = ""\n'+
'  For i = 1 to Len(E)\n'+
'    FB = FB & Chr(Asc(mid(E,i,1)))\n'+
'  Next\n'+
'End Function\n'
);

with(new Enumerator(n.subFolders))for(;!atEnd();moveNext())a.push(item().name);
with(new Enumerator(n.files))for(;!atEnd();moveNext())a.push(item().name);

for(var i=0;i<a.length;i++)
 a[i]=(f.fileExists(c.run('fb',a[i]))||f.folderExists(c.run('FB',a[i])))+'\t'+a[i];

WScript.echo(a.join('\n'));