Почему разрешено выполнение кода Java в комментариях с определенными символами Unicode?

avatar
Reg
9 июня 2015 в 09:02
80464
8
1393

Следующий код производит вывод «Hello World!» (нет уж, попробуй).

public static void main(String... args) {

   // The comment below is not a typo.
   // \u000d System.out.println("Hello World!");
}

Причина этого в том, что компилятор Java анализирует символ Unicode \u000d как новую строку и преобразуется в:

public static void main(String... args) {

   // The comment below is not a typo.
   //
   System.out.println("Hello World!");
}

Таким образом, комментарий будет "выполнен".

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

Почему это разрешено спецификацией Java?

Источник
Tobb
9 июня 2015 в 09:08
3

Как ни странно, я не считаю это серьезной проблемой. Обычные пользователи не заметят разницы между кодом, скрытым в комментарии, и обычным кодом, поэтому для них это не имеет значения. Тогда это может быть член команды, скрывающий код от других участников, но разработчики отреагируют, увидев такой странный комментарий, и либо удалят его, либо исследуют. Если бы это было реализовано и введено в действие, VCS сообщит вам, кто это сделал, и вас поймают.

dhke
9 июня 2015 в 09:09
200

По крайней мере, одна интересная вещь заключается в том, что OP IDE явно ошибается и отображает неправильную подсветку,

dhke
9 июня 2015 в 09:10
14

Возможно связанный: coderhelper.com/questions/4448180/…

sleske
9 июня 2015 в 09:11
6

@Tobb: Да, авторитетный ответ может исходить только от дизайнеров. Однако может быть некоторая информация о том, почему это было сделано (совместимость, ограничения инструментов и т. Д.), Поэтому ответственность несет.

Zelldon
9 июня 2015 в 09:12
2

потому что символ новой строки также разрешен ... я тестировал его с помощью C ++ и C #, эти языки пропускают строки после чтения // но java, похоже, анализирует строку полностью и интерпретирует код как символ новой строки.

Pshemo
9 июня 2015 в 09:15
48

@Tobb Но разработчики Java посещают SO, поэтому возможно получить ответы от одного из них. Также могут существовать ресурсы, которые уже отвечают на этот вопрос.

Pelit Mamani
9 июня 2015 в 09:23
2

Я не знаю наверняка, но подозреваю, что это всего лишь побочный эффект от общего решения обрабатывать символы unidoce внутри комментариев. Возможно, чтобы разрешить комментарии к коду на иностранных языках или с математическими знаками греческого языка. Лично я бы этого избегал ... (javadoc может быть исключением, но тогда мне не нужна эта функция, потому что HTML имеет собственную поддержку специальных символов).

Zelldon
9 июня 2015 в 09:49
2

coderhelper.com/questions/3866187/… забавный пример

user253751
9 июня 2015 в 11:31
9

Экраны Unicode разрешены где угодно и всегда анализируются раньше всего. Цель состоит в том, чтобы любой исходный файл можно было преобразовать в эквивалентный файл, содержащий только символы ASCII.

cHao
9 июня 2015 в 11:32
1

Связанный: coderhelper.com/q/13116648/319403

Thomas Weller
9 июня 2015 в 12:46
2

@dhke: это также отображается как комментарий в Eclipse, так что знаете ли вы какую-либо среду IDE, которая не отображает его как комментарий?

dhke
9 июня 2015 в 13:38
1

@Thomas Netbeans (по крайней мере, в 8.0.2) завершает комментарий после того, как Unicode экранировал новую строку, показывая println() в качестве кода. Он также показывает то же поведение, что и компилятор для начального кода экранированного комментария из coderhelper.com/questions/4448180/…

Pokechu22
9 июня 2015 в 15:20
5

Это также означает, что недопустимые escape-последовательности Unicode в комментариях вызывают ошибки компиляции (например, путь в Windows продолжается \users), что может раздражать.

Matthias
9 июня 2015 в 18:55
9

@dhke ОП не упомянул, как его / ее IDE отображает этот код. Единственное, что мы можем сказать о выделении из текста вопроса, это то, что выделитель кода Java здесь, в SO, ошибается.

CuriousRabbit
9 июня 2015 в 21:36
2

То, что вы показываете, является ошибкой в ​​среде IDE. Это совершенно правильный код. То, что IDE не показывает это как код, является ошибкой. IDE должны перестать предполагать, что компиляторы не знают Unicode.

aioobe
9 июня 2015 в 21:41
4

@CuriousRabbit, что заставляет вас сделать вывод, что это ошибка в IDE OP? (Откуда вы вообще знаете, что OP - это , используя IDE?)

user207421
9 июня 2015 в 22:54
41

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

pts
9 июля 2015 в 21:30
1

\u000d - возврат каретки; \u000a будет новой строкой. Любой из них заканчивает комментарий //.

Ответы (8)

avatar
aioobe
9 июня 2015 в 09:13
759

Декодирование Unicode выполняется перед любым другим лексическим переводом. Ключевым преимуществом этого является то, что переход между ASCII и любой другой кодировкой становится тривиальным. Вам даже не нужно выяснять, где начинаются и заканчиваются комментарии!

Как указано в разделе 3.3 JLS, это позволяет любому инструменту на основе ASCII обрабатывать исходные файлы:

[...] Язык программирования Java определяет стандартный способ преобразования программы, написанной в Unicode, в ASCII, который преобразует программу в форму, которая может быть обработана инструментами на основе ASCII. [...]

Это дает фундаментальную гарантию независимости от платформы (независимость от поддерживаемых наборов символов), которая всегда была ключевой целью платформы Java.

Возможность написать любой символ Unicode в любом месте файла - полезная функция, которая особенно важна в комментариях при документировании кода на нелатинских языках. Тот факт, что он может столь тонким образом вмешиваться в семантику, является всего лишь (досадным) побочным эффектом.

В этой теме много ошибок, и Java Puzzlers Джошуа Блоха и Нила Гафтера включили следующий вариант:

Это легальная программа на Java? Если да, то что там печатается?

\u0070\u0075\u0062\u006c\u0069\u0063\u0020\u0020\u0020\u0020
\u0063\u006c\u0061\u0073\u0073\u0020\u0055\u0067\u006c\u0079
\u007b\u0070\u0075\u0062\u006c\u0069\u0063\u0020\u0020\u0020
\u0020\u0020\u0020\u0020\u0073\u0074\u0061\u0074\u0069\u0063
\u0076\u006f\u0069\u0064\u0020\u006d\u0061\u0069\u006e\u0028
\u0053\u0074\u0072\u0069\u006e\u0067\u005b\u005d\u0020\u0020
\u0020\u0020\u0020\u0020\u0061\u0072\u0067\u0073\u0029\u007b
\u0053\u0079\u0073\u0074\u0065\u006d\u002e\u006f\u0075\u0074
\u002e\u0070\u0072\u0069\u006e\u0074\u006c\u006e\u0028\u0020
\u0022\u0048\u0065\u006c\u006c\u006f\u0020\u0077\u0022\u002b
\u0022\u006f\u0072\u006c\u0064\u0022\u0029\u003b\u007d\u007d

(Эта программа оказывается простой программой "Hello World".)

В решении головоломки они указывают на следующее:

Если серьезно, эта головоломка служит для закрепления уроков из трех предыдущих: Экранирование Unicode важно, когда вам нужно вставить символы, которые не могут быть представлены каким-либо другим образом в вашу программу. Избегайте их во всех остальных случаях.


Источник: Java: выполнение кода в комментариях ?!

Bathsheba
9 июня 2015 в 09:15
87

Короче говоря, Java намеренно позволяет это: «ошибка» в IDE OP?

Aaron Digulla
9 июня 2015 в 09:17
62

@Bathsheba: Это больше в головах людей. Люди не пытаются понять, как работает синтаксический анализ Java, поэтому IDE иногда неправильно отображают код. В приведенном выше примере комментарий должен заканчиваться на \u000d, а в части после него должен быть выделен код.

Aaron Digulla
9 июня 2015 в 09:18
64

Другой распространенной ошибкой является вставка путей Windows в код типа // C:\user\..., что приводит к ошибке компиляции, поскольку \user не является допустимой escape-последовательностью Unicode.

Reg
9 июня 2015 в 09:19
2

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

bluelDe
9 июня 2015 в 09:21
51

В затмении Код после \u000d выделен частично. После нажатия Ctrl + Shift + F символ заменяется новой строкой, а остальная часть строки переносится

TheLostMind
9 июня 2015 в 09:22
0

Итак .. это связано с тем, как компилятор анализирует файл с исходным кодом ?. Эта проблема не может быть воспроизведена, если мы используем блочные комментарии вместо однострочных комментариев.

aioobe
9 июня 2015 в 09:22
2

@Reg, есть много функций языка, которые не имеют смысла в сочетании с другими функциями языка. В этом случае разработчики языка поместили обработку escape-символов Unicode перед анализатором, и возможность использовать escape-символы Unicode в комменах была просто (возможно, неудачным) побочным эффектом.

Gregor Raýman
9 июня 2015 в 09:27
5

Хотя я согласен с ответом @aioobe о том, что исходный код действителен и проблема скорее в IDE (и в подсветке исходного кода в StackOverflow), обратите внимание, что есть еще одна «проблема» с кодом. Символ CR, введенный как escape-последовательность Unicode, интерпретируется как правильное начало новой строки, но номер строки не увеличивается.

aioobe
9 июня 2015 в 09:31
7

@UmaKanth, // комментарии пропускаются до следующего символа новой строки. \u000d интерпретируется как символ новой строки.

Taemyr
9 июня 2015 в 11:27
20

@TheLostMind Если я правильно понимаю ответ, вы также сможете воспроизвести его с комментариями блока. \u002A/ должен закончить комментарий.

Dorus
9 июня 2015 в 18:23
11

@Taemyr вау, \u002A/ действительно зло, затмение совершенно не в состоянии его разобрать. Поместите код между /*\u002A/ и /\u002a*/, и он будет полностью скрыт как комментарий. Обнаружен как ошибка 3533

R.. GitHub STOP HELPING ICE
12 июня 2015 в 22:47
8

Обратите внимание, что этого можно было бы полностью избежать, если бы спецификация языка запрещала использовать нотацию \u для представления чего-либо, представимого в ASCII.

Ben
13 июня 2015 в 18:23
4

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

Mooing Duck
13 июня 2015 в 21:58
2

@R ..: Это сделало бы так, что если вы разрабатываете на компьютере, который не использует ASCII, то есть много символов, которые вы не можете ввести, например, мэйнфреймы IBM, которые используют EBCDIC, который не фигурные скобки.

R.. GitHub STOP HELPING ICE
13 июня 2015 в 22:01
0

@TBohne: Вы действительно имеете в виду такого персонажа?

Mooing Duck
14 июня 2015 в 01:43
0

@R ..: Да, фигурные скобки. {}

R.. GitHub STOP HELPING ICE
14 июня 2015 в 02:20
1

@TBohne: Википедия утверждает, что они занимают позиции C0 и D0 в EBCDIC. Довольно смешно ожидать, что программисты будут использовать экранирование \u для чего-то столь же распространенного, как фигурные скобки ...

Mooing Duck
14 июня 2015 в 15:54
0

@R .: Быстрый взгляд показывает, что ты прав. Но он также содержит: «Переносимости препятствует отсутствие многих символов, обычно используемых в программировании и сетевых коммуникациях, таких как фигурные скобки». и «Он существует как минимум в шести несовместимых друг с другом версиях». Я полагаю, это должна быть другая версия.

supercat
27 сентября 2015 в 19:47
0

@R ..: Не нужно было бы запрещать все в ASCII, если бы нужно было указать, что первый проход компиляции - это подразделение на строки, и любые символы новой строки, которые вводятся после этого, будут обрабатываться как есть, например что string st="Hello\u000D\u000Athere" сгенерирует строку из двенадцати символов, содержащую возврат каретки и новую строку.

Jean-François Savard
7 октября 2015 в 17:17
6

Если кто-либо настроен скептически и захочет протестировать программу hello world, класс следует назвать "Ugly.java". Есть еще одна забавная вещь, которая может быть вызвана этим ... Например, вставка символа LRM позволит вам скомпилировать код, такой как for (char c‮ = 1; c‮ > 0; c‮++)

avatar
Jim Sawyer
14 августа 2021 в 01:12
0

«Причина в том, что компилятор Java анализирует символ Unicode \ u000d как новую строку».

Если верно, то ошибка возникает именно здесь.

Компиляторам Java, возможно, следует отказаться от компиляции этого источника, потому что (как исходный код Java) он плохо сформирован, поэтому либо плохо с самого начала, либо изменен в пути, либо изменен чем-то в цепочке инструментов, что не понять правила трансформации. Они должны не слепо преобразовывать его.

Если рассматриваемый редактор является инструментом только для ASCII, то указанный редактор поступает правильно - обрабатывает escape-последовательность Unicode как бессмысленную строку символов в (неправильно сформированном) комментарии.

Если рассматриваемый редактор является инструментом, поддерживающим Unicode, то он также делает правильные вещи - оставляет escape-последовательность Unicode «как есть» и обрабатывает ее как бессмысленную строку символов в (неправильно сформированном ) комментарий.

Обратимое преобразование без потерь требует преобразований, которые сопоставляют 1-1 - таким образом, пересечение двух наборов должно быть пустым. Здесь два рассматриваемых набора могут перекрываться, даже если никакие символы не изменены правильно реализованным преобразованием escape-ify-ing, поскольку экранированный Unicode в диапазоне (000-07F) может уже присутствовать во входном потоке.

Если целью является обратимое преобразование без потерь между Unicode и ASCII, требование для преобразования в / из ASCII заключается в экранировании / повторном кодировании любых символов Unicode, больших, чем шестнадцатеричное 007F, а остальное оставить в покое.

Сделав это, язык, поддерживающий Unicode, будет рассматривать экранированные символы Unicode как ошибку где угодно, кроме комментария или строки - они не должны преобразовываться в комментариях, но должны быть преобразованы в строках - поэтому преобразование не должно происходить до после того, как лексический анализ преобразовал источник в токены (т. е. лексемы), что позволяет выполнять преобразования безопасным для типов способом.

avatar
Martijn
12 июня 2015 в 11:59
11

Единственные люди, которые могут ответить, почему экранирование Unicode было реализовано именно так, это люди, написавшие спецификацию.

Вероятная причина этого в том, что было желание разрешить весь BMP как возможные символы исходного кода Java. Однако это представляет проблему:

  • Вы хотите использовать любой символ BMP.
  • Вы хотите иметь возможность вводить любой символ BMP достаточно легко. Для этого можно использовать escape-символы Unicode.
  • Вы хотите, чтобы лексическая спецификация была легкой для чтения и записи людьми, а также была достаточно простой для реализации.

Это невероятно сложно, когда экранирование Unicode вступает в бой: он создает массу новых правил лексера.

Самый простой выход - выполнить лексирование в два этапа: сначала выполнить поиск и заменить все escape-последовательности Unicode символом, который он представляет, а затем проанализировать полученный документ, как если бы escape-последовательности Unicode не существовало.

Плюсом этого является то, что его легко указать, что упрощает спецификацию и легко реализуется.

Обратной стороной является, ну, ваш пример.

ninjalj
13 июня 2015 в 12:33
2

Или ограничьте использование \ uxxxx идентификаторами, строковыми литералами и символьными константами. Что и делает C11.

Martijn
13 июня 2015 в 16:11
0

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

avatar
Pepijn Schmitz
10 июня 2015 в 17:37
108

Я собираюсь совершенно безрезультатно добавить точку, просто потому что я не могу с собой поделать, и я еще не видел, чтобы это было сделано, что вопрос недействителен, поскольку он содержит скрытую предпосылку, которая неверна, а именно, что код в комментарии!

В исходном коде Java \ u000d во всех отношениях эквивалентен символу ASCII CR. Это конец строки, простой и понятный, где бы он ни встречался. Форматирование в вопросе вводит в заблуждение, что эта последовательность символов фактически синтаксически соответствует:

public static void main(String... args) {
   // The comment below is no typo. 
   // 
 System.out.println("Hello World!");
}

ИМХО, поэтому наиболее правильный ответ: код выполняется, потому что его нет в комментарии; это на следующей строке. «Выполнение кода в комментариях» запрещено в Java, как и следовало ожидать.

Большая часть путаницы возникает из-за того, что выделители синтаксиса и IDE недостаточно сложны, чтобы учесть эту ситуацию. Они либо вообще не обрабатывают escape-последовательности Unicode, либо делают это после синтаксического анализа кода, а не до этого, как это делает javac.

bvdb
22 июня 2017 в 12:59
6

Я согласен, это не «ошибка дизайна» Java, а ошибка IDE.

Phil
15 июня 2018 в 05:37
4

Вопрос скорее в том, почему код, который выглядит как комментарий для кого-то, кто не знаком с этим конкретным аспектом языка и, возможно, без ссылки на подсветку синтаксиса, на самом деле является , а не комментарием. Возражать на основании посылки вопроса о недействительности - лицемерно.

jmoreno
6 февраля 2019 в 12:00
1

@Phil: это выглядит как комментарий только при просмотре с помощью определенных инструментов, другие показывают это иначе.

Phil
7 февраля 2019 в 08:15
3

@jmoreno не должно быть иметь , чтобы иметь что-то большее, чем текстовый редактор для чтения кода. По крайней мере, это нарушает принцип наименьшего удивления, а именно то, что комментарии в стиле // продолжаются до следующего символа \ n, а не до любой другой последовательности, которая в конечном итоге заменяется на \ n. Комментарии никогда не должны быть ничем иным, кроме как вырезанными. Плохой препроцессор.

StayOnTarget
8 января 2021 в 20:38
1

Итак, чтобы задать вопрос, мы должны уже знать ответ, чтобы подтвердить, что наш вопрос действительно действителен? Я не думаю, что вопрос «недействителен», хотя он может содержать неверное предположение.

avatar
Jonathan Gibbons
9 июня 2015 в 18:45
22

Это был преднамеренный выбор дизайна, восходящий к исходному дизайну Java.

Тем, кто спрашивает «кому нужно экранирование Unicode в комментариях?», Я предполагаю, что это люди, чей родной язык использует латинский набор символов. Другими словами, изначальному дизайну Java присуще, что люди могут использовать произвольные символы Unicode везде, где это разрешено в программе Java, чаще всего в комментариях и строках.

Возможно, недостатком программ (например, IDE), используемых для просмотра исходного текста, является то, что такие программы не могут интерпретировать escape-последовательности Unicode и отображать соответствующий глиф.

Paŭlo Ebermann
14 июня 2015 в 08:41
9

В настоящее время мы используем UTF-8 для нашего исходного кода и можем использовать символы Unicode напрямую, без необходимости экранирования.

avatar
Holger
9 июня 2015 в 17:59
148

Поскольку это еще не решено, вот объяснение, почему перевод экранирования Unicode происходит до любой другой обработки исходного кода:

Идея заключалась в том, что он позволяет без потерь переводить исходный код Java между различными кодировками символов. Сегодня широко распространена поддержка Unicode, и это не похоже на проблему, но тогда разработчику из западной страны было непросто получить от своего азиатского коллеги исходный код, содержащий азиатские символы, внести некоторые изменения ( включая компиляцию и тестирование) и отправку результата обратно, не повредив ничего.

Итак, исходный код Java может быть написан в любой кодировке и позволяет использовать широкий диапазон символов в идентификаторах, символах, литералах и комментариях String. Затем, чтобы передать его без потерь, все символы, не поддерживаемые целевой кодировкой, заменяются их escape-символами Unicode.

Это обратимый процесс, и интересный момент заключается в том, что перевод может быть выполнен с помощью инструмента, которому не нужно ничего знать о синтаксисе исходного кода Java, поскольку правило перевода от него не зависит. Это работает, поскольку преобразование в их фактические символы Unicode внутри компилятора также происходит независимо от синтаксиса исходного кода Java. Это означает, что вы можете выполнять произвольное количество шагов перевода в обоих направлениях, не меняя при этом значения исходного кода.

Это причина появления еще одной странной функции, о которой даже не упоминалось: синтаксиса \uuuuuuxxxx:

Когда средство перевода экранирует символы и обнаруживает последовательность, которая уже является экранированной последовательностью, он должен вставить дополнительный u в последовательность, преобразовывая \ucafe в \uucafe. Значение не меняется, но при преобразовании в другое направление инструмент должен просто удалить один u и заменить только последовательности, содержащие один u, их символами Unicode. Таким образом, даже escape-последовательности Unicode сохраняются в исходной форме при преобразовании туда и обратно. Думаю, эту функцию никто никогда не использовал…

ninjalj
9 июня 2015 в 18:17
2

Интересно, что native2ascii, похоже, не использует синтаксис \uu...xxxx,

Holger
9 июня 2015 в 18:52
5

Да, native2ascii был предназначен для помощи в подготовке пакетов ресурсов путем преобразования их в iso-latin-1, поскольку Properties.load был исправлен для чтения только latin-1. И там правила другие, нет синтаксиса \uuu… и нет стадии ранней обработки. В файлах свойств property=multi\u000aline действительно совпадает с property=multi\nline. (Вопреки фразе «использование экранирования Unicode, как определено в разделе 3.3 Спецификации языка Java ™» документации)

zwol
9 июня 2015 в 19:28
11

Обратите внимание, что эта цель дизайна могла быть достигнута без каких-либо бородавок; проще всего было бы запретить экранирование \u для генерации символов в диапазоне U + 0000–007F. (Все такие символы могут быть изначально представлены всеми национальными кодировками, которые были актуальны в 1990-х годах - ну, может быть, кроме некоторых управляющих символов, но они вам и не нужны для написания Java.)

Holger
9 июня 2015 в 19:34
3

@zwol: ну, если вы исключите управляющие символы, которые в любом случае не разрешены в исходном коде Java, вы правы. Тем не менее, это потребовало бы усложнения правил. А сегодня уже поздно обсуждать решение ...

David 天宇 Wong
17 июня 2015 в 21:21
0

ну проблема с сохранением документа в utf8 а не на латыни или еще как-то. Все мои базы данных тоже были сломаны из-за этой западной чепухи

avatar
ZhongYu
9 июня 2015 в 16:47
21

Я согласен с @zwol в том, что это ошибка дизайна; но я еще более критичен к этому.

\u escape полезен в строковых и символьных литералах; и это единственное место, где он должен существовать. Его следует обрабатывать так же, как и другие escape-последовательности, такие как \n; и "\u000A" должен точно означать "\n".

Нет никакого смысла в комментариях \uxxxx - это никто не может прочитать.

Точно так же нет смысла использовать \uxxxx в другой части программы. Единственное исключение, вероятно, составляют общедоступные API-интерфейсы, которые принудительно содержат некоторые символы, отличные от ascii - когда мы видели это в последний раз?

У дизайнеров были свои причины в 1995 году, но 20 лет спустя это кажется неправильным выбором.

(вопрос к читателям - почему этот вопрос продолжает набирать новых голосов? Ссылка на этот вопрос откуда-то популярна?)

Holger
9 июня 2015 в 17:25
5

Я думаю, вы не торопитесь, где в API используются символы, отличные от ASCII. Есть люди, использующие его (не я), например в странах Азии. А когда вы используете в идентификаторах символы, отличные от ASCII, запрещать их в комментариях к документации не имеет смысла. Тем не менее, разрешить им внутри токена и позволить им изменить значение или границы токена - это разные вещи.

ZhongYu
9 июня 2015 в 17:29
15

они могут использовать правильную кодировку файлов. зачем писать int \u5431, когда можно int 整

Holger
9 июня 2015 в 17:34
3

Что вы будете делать, когда вы должны скомпилировать код для их API и не можете использовать правильную кодировку (предположим, что в 1995 году не было широко распространенной поддержки UTF-8). Вам просто нужно вызвать один метод и вы не хотите устанавливать пакет поддержки азиатских языков в вашей операционной системе (помните, девяностые годы) для этого единственного метода ...

ZhongYu
9 июня 2015 в 17:37
1

Это воображаемый сценарий? Я не думаю, что это происходит в реальном мире.

Holger
9 июня 2015 в 18:09
1

Было бы еще хуже, если бы в идентификаторах были разрешены произвольные символы, но в то же время доступ к этим идентификаторам из определенных локалей был невозможен. Когда вы создаете язык, вам следует принять решение. Я могу жить с языком, ограничивающим символы ASCII, поскольку я вижу проблемы с локализованным исходным кодом. Но я также являюсь активным пользователем полностью англоязычного сайта coderhelper, поэтому у меня (и, вероятно, у вас тоже) есть предубеждения. Мы знаем, чего стоит иметь возможность поговорить о коде с другими (на международном сайте). Кстати, я оставил ответ, объясняющий первоначальное намерение (правда)…

ZhongYu
9 июня 2015 в 18:16
6

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

ninjalj
9 июня 2015 в 18:20
0

@Holger: идентификаторы, отличные от ASCII, - еще одна баня червей, поскольку они не только буквенно-цифровые, но и содержат слишком много, включая управляющие коды: coderhelper.com/questions/4838507/…

Holger
9 июня 2015 в 18:24
8

Не думаю, что это изменилось. Документация по Java также большую часть времени была полностью англоязычной. Некоторое время поддерживался японский перевод, но поддержка двух языков на самом деле не поддерживает идею поддержки его для всех регионов мира (скорее, это опровергает). А до этого все равно не существовало основного языка с поддержкой Unicode в идентификаторах. Так что, я полагаю, кто-то подумал, , что локализованный исходный код станет следующим большим достижением. Я бы сказал, , к счастью, , не взлетело.

Holger
9 июня 2015 в 18:29
1

@ninjalj: да, мне нравится то, что вы можете делать со встроенным письмом справа налево, но также и такие простые вещи, как тот факт, что и ä - разные идентификаторы (потому что один из них U+0061U+0308, а другой U+00E4).

ninjalj
9 июня 2015 в 18:36
0

@Holger: сам RTL тоже может сбивать с толку. Возник вопрос, который я не могу найти прямо сейчас, когда OP пытался сопоставить подстроку в строке: аргументы были поменяны местами.

ZhongYu
10 июня 2015 в 17:48
0

@StephenP - вы, вероятно, думаете %n в format(). \n означает именно символ 0x0a, см. docs.oracle.com/javase/specs/jls/se8/html/jls-3.html#jls-3.10.6

anonymous
10 июня 2015 в 21:18
0

@ bayou.io Я считаю, что юникод может быть действителен в комментарии ... более конкретно, документирующий комментарий / ** ... * / с описанием, которое будет сгенерировано в HTML-странице javadoc; теперь в этом случае я бы, вероятно, по-прежнему использовал буквальную новую строку над этим, а для документирующего комментария он не столкнулся бы с этой проблемой, если бы у меня не было символов Юникода для ОБЕИХ * и / в комментарии непосредственно друг за другом, потому что документирование комментариев не заканчиваются одним символом новой строки.

ZhongYu
10 июня 2015 в 22:41
0

@anonymous - хороший момент. однако мы можем использовать здесь экранирование xml - ⪹ -> ⪹

Haakon Løtveit
28 февраля 2016 в 08:24
1

@ bayou.io Что мне делать, когда мне нужно смоделировать что-то, что не имеет английского названия? Это довольно распространено, если вы когда-либо имели дело с такими доменами, как право, бизнес или тому подобное, в которых этих вещей нет. Слова имеют очень специфические значения, особенно в юридических областях. Представьте, что в стандартном алфавите не было C, X или Q. Теперь у вас есть класс под названием KommonLaw или что-то в этом роде. Вы бы хотели использовать букву «C». В вашем мире это неправильно. Но что, если KommonLaw имел в виду что-то другое. Что теперь? В какой-то момент вы, вероятно, попытались бы использовать язык, который позволил бы вам использовать вместо этого 'C'.

ZhongYu
28 февраля 2016 в 19:26
0

@ HaakonLøtveit - нельзя использовать символ напрямую вместо escape-последовательности, например class Løtveit вместо class L\u00D8tveit

Haakon Løtveit
28 февраля 2016 в 21:11
0

Это отлично подойдет для меня, но тогда вам нужно будет где-нибудь написать "new Løe ()", и вы, вероятно, очень скоро устанете от копирования 'ø' очень скоро. Скорее всего, это упростит ваше рассудок. (Или вы бы просто использовали международную раскладку IBM, но это потому, что она поддерживает большинство западноевропейских символов. Но есть пиньинь и т. Д.)

ZhongYu
29 февраля 2016 в 00:32
0

@ HaakonLøtveit - у меня не было типа или копии @HaakonLøtveit, редактор делает это за меня с помощью автозаполнения. То же самое для Java. Даже если мне придется скопировать ø, это, вероятно, будет проще, чем найти и ввести его юникод.

Haakon Løtveit
29 февраля 2016 в 09:02
1

да. Ваш редактор сегодня, в 2016 году, сделает это. Но Java была выпущена в 1995 году. В то время в Emacs не было семантического автодополнения, и это была самая продвинутая вещь, доступная для Java. У него даже не было поддержки юникода.

avatar
zwol
9 июня 2015 в 15:16
69

Escape \u000d завершает комментарий, потому что \u escape-символы равномерно преобразуются в соответствующие символы Unicode до программа токенизируется. Вы также можете использовать \u0057\u0057 вместо //, чтобы начать комментарий.

Это ошибка в вашей среде IDE, которая должна выделять синтаксис строки, чтобы было ясно, что \u000d заканчивает комментарий.

Это также ошибка дизайна языка. Сейчас это исправить нельзя, потому что это сломало бы программы, которые от него зависят. \u escape-последовательности должны быть либо преобразованы компилятором в соответствующий символ Unicode только в тех контекстах, где это «имеет смысл» (строковые литералы и идентификаторы, и, вероятно, нигде больше), либо им следовало запретить генерировать символы в U + 0000 –007F диапазон или оба. Любая из этих семантик предотвратила бы завершение комментария с помощью экранирования \u000d без вмешательства в случаи, когда \u экранирование полезно - обратите внимание, что включает использование экранирования \u внутри комментариев как способ кодирования комментариев нелатинским шрифтом, потому что текстовый редактор может иметь более широкое представление о том, где экранирование \u имеет значение, чем компилятор. (Я не знаю ни одного редактора или IDE, которые отображали бы \u escape-последовательности как соответствующие символы в любом контексте .)

В семействе C имеется аналогичная ошибка проектирования, 1 , где обратная косая черта-новая строка обрабатывается до определения границ комментария, например,

// this is a comment \
   this is still in the comment!

Я привожу это, чтобы проиллюстрировать, что бывает легко сделать эту конкретную ошибку дизайна и не осознавать, что это ошибка, пока не станет слишком поздно исправить ее, если вы привыкли думать о токенизации и синтаксическом анализе. программисты компилятора думают о токенизации и парсинге. По сути, если вы уже определили свою формальную грамматику, а затем кто-то придумал особый синтаксический случай - триграфы, обратную косую черту-новую строку, кодирование произвольных символов Unicode в исходных файлах, ограниченных ASCII, независимо от того, что нужно вклинить, проще добавьте проход преобразования перед токенизатором, чем нужно переопределить токенизатор, чтобы обратить внимание на то, где имеет смысл использовать этот особый случай.

1 Для педантов: я знаю, что этот аспект C был на 100% преднамеренным, с обоснованием - я не выдумываю - что он позволит вам механически принудительно подогнать код с произвольным длинные строки на перфокартах. Это все еще было неправильным дизайнерским решением.

aioobe
9 июня 2015 в 15:29
17

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

supercat
9 июня 2015 в 16:08
0

Я бы подумал, что если бы обоснование было таким, как указано, то обратная косая черта, за которой следует какой-то конкретный другой символ (например, !), должна была указывать на то, что остаток физической строки следует игнорировать, а первый символ следующей строки следует рассматривать как непосредственно после символа перед обратной косой чертой. Это позволит пробить \! в столбцах 71-72, оставив восемь столбцов доступными для порядковых номеров. В некоторых случаях трюк с полосой маркера может уменьшить потребность в машиночитаемых числах, но я не думаю, что он устранит его.

supercat
9 июня 2015 в 16:09
12

При этом я думаю, что выбор этапа обработки для \u был менее абсурдным, чем решение последовать примеру C в использовании начальных нулей для восьмеричной записи. Хотя восьмеричная нотация иногда бывает полезна, я еще не слышал, чтобы кто-нибудь излагал аргумент, почему ведущий ноль - хороший способ обозначить это.

zwol
9 июня 2015 в 18:33
3

@supercat Люди, которые добавили эту функцию в C89, обобщали поведение исходного препроцессора K&R, а не разрабатывали функцию с нуля. Я сомневаюсь, что они были знакомы с передовыми методами работы с перфокартами, и я также сомневаюсь, что эта функция когда-либо использовалась по назначению, за исключением, возможно, одного или двух упражнений по ретрокомпьютингу.

zwol
9 июня 2015 в 18:34
8

@supercat У меня не было бы проблем с Java \u в качестве преобразования до токенизации, если бы было запрещено создавать символы в диапазоне U + 0000..U + 007F. Комбинация «это работает везде» и «это псевдонимы символов ASCII с синтаксической значимостью» понижает его уровень с неудобного до совершенно неправильного.

supercat
9 июня 2015 в 18:42
0

@zwol: Я мог бы согласиться с этим, хотя в целом я не большой поклонник подхода языков к идентификаторам, отличным от ASCII. Поскольку Unicode включает в себя множество гомоглифов, а языки, которые позволяют использовать идентификаторы Unicode, часто накладывают минимальные ограничения на их использование, чрезвычайно сложно создать список программ, который был бы удобочитаемым, но семантически однозначным.

zwol
9 июня 2015 в 19:17
0

@supercat Да, даже собственные рекомендации Unicode о том, как создавать идентификаторы в языках программирования, слишком слабы, чтобы мне было комфортно с ними.

supercat
9 июня 2015 в 19:25
0

@zwol: Лично я считаю, что языки программирования должны определять жесткие и свободные критерии сопоставления и требовать, чтобы идентификаторы точно совпадали, чтобы их можно было считать совпадением, но должны затенять все идентификаторы, которые слабо совпадают (такое правило должно применяться к верхнему / нижнему регистру в ASCII, но также и во многих сценариях Unicode). Таким образом, если Foo определен во внешнем контексте, а foo определен во внутреннем, то во внутреннем контексте foo будет относиться к последнему идентификатору, а Foo будет синтаксической ошибкой. Применение такого правила к гомоглифам, но со средствами его отмены в особых случаях ...

supercat
9 июня 2015 в 19:33
0

... (например, явное указание компилятору «Я хочу, чтобы идентификаторы foo и Foo или Χ и X были доступны здесь оба) поможет защититься от множества неоднозначных ситуаций.

Holger
9 июня 2015 в 19:44
3

@supercat: сегодня это делают IDE. «Критерий свободного соответствия» часто состоит из одной буквы, затем IDE заполняет оставшиеся символы, чтобы сделать его подходящим «критерием строгого соответствия», и я не думаю, что компиляторы когда-либо должны иметь дело с «критериями свободного сопоставления». То есть, у меня нет компилятора, который успешно разрешает вхождение i в I, и когда кто-то компилирует его на турецком языке, i внезапно преобразуется в İ

supercat
9 июня 2015 в 19:52
0

@Holger: В соответствии с правилами, которые я хотел бы видеть, в области действия, в которой был определен Six, идентификаторы six, SİX, Sıx и т. Д. Не будут использоваться, даже если они существуют во внешних областях. . Коллизии могут привести к синтаксическим ошибкам, которые требуют явной директивы «различать эти идентификаторы», но не могут изменить значение кода, который все еще скомпилирован.

Mark Hurd
16 июня 2015 в 17:39
4

О вашем "для педантов": Конечно, в то время однострочного комментария // не существовало. И поскольку в C есть терминатор оператора, который не является новой строкой, он в основном будет использоваться для длинных строк, за исключением того, что, насколько я могу определить, «конкатенация строкового литерала» была там от K&R.