미스터리
자바 식별자에서 어떤 문자가 허용되었는지 정확하게 탐색하면서 매우 궁금한 점을 발견하여 버그라고 확신합니다.Java가 식별자에서 제어 문자를 허용하는 이유는 무엇입니까?
Java 식별자가 Unicode 속성이 ID_Start
인 문자로 시작하고 뒤에 ID_Continue
속성이있는 문자로 시작하는 요구 사항을 준수한다는 것을 알았 으면합니다. 단, 밑줄과 달러 기호는 예외입니다. 그게 사실이 아니라는 것을 알았고, 내가 발견 한 것은 정상적인 식별자에 대한 다른 아이디어 나 생각과는 극단적 인 차이가 있다는 것입니다.
짧은 데모
은 다음과 데모는 ASCII의 ESC 문자 (진수 033)은 자바 식별자에 허용되는 것을 증명 고려 :
$ perl -le 'print qq(public class escape { public static void main(String argv[]) { String var_\033 = "i am escape: \033"; System.out.println(var_\033); }})' > escape.java
$ javac escape.java
$ java escape | cat -v
i am escape: ^[
그것은하지만, 그것보다 더 나쁜입니다. 사실, 거의 무한히 악화됩니다. NULL도 허용됩니다! 그리고 심지어 식별 문자가 아닌 수천 개의 다른 코드 포인트. 필자는 솔라리스, 리눅스, 그리고 다윈을 운영하는 맥에서 이것을 시험해 보았습니다. 여기에 긴 데모
이 모든 예기치 않은 코드가 자바는 매우 outrageuosly 법적 식별자 이름의 일부로 수 있다는 지적이 표시됩니다 테스트 프로그램입니다. 또 다른 데모 여기
$ perl test-java-idchars 0 0x20
testing \p{Control} U+0000 NULL...is LEGAL in Java identifiers.
testing \p{Control} U+0001 START OF HEADING...is LEGAL in Java identifiers.
testing \p{Control} U+0002 START OF TEXT...is LEGAL in Java identifiers.
testing \p{Control} U+0003 END OF TEXT...is LEGAL in Java identifiers.
testing \p{Control} U+0004 END OF TRANSMISSION...is LEGAL in Java identifiers.
testing \p{Control} U+0005 ENQUIRY...is LEGAL in Java identifiers.
testing \p{Control} U+0006 ACKNOWLEDGE...is LEGAL in Java identifiers.
testing \p{Control} U+0007 BELL...is LEGAL in Java identifiers.
testing \p{Control} U+0008 BACKSPACE...is LEGAL in Java identifiers.
testing \p{Control} U+000B LINE TABULATION...is forbidden in Java identifiers.
testing \p{Control} U+000E SHIFT OUT...is LEGAL in Java identifiers.
testing \p{Control} U+000F SHIFT IN...is LEGAL in Java identifiers.
testing \p{Control} U+0010 DATA LINK ESCAPE...is LEGAL in Java identifiers.
testing \p{Control} U+0011 DEVICE CONTROL ONE...is LEGAL in Java identifiers.
testing \p{Control} U+0012 DEVICE CONTROL TWO...is LEGAL in Java identifiers.
testing \p{Control} U+0013 DEVICE CONTROL THREE...is LEGAL in Java identifiers.
testing \p{Control} U+0014 DEVICE CONTROL FOUR...is LEGAL in Java identifiers.
testing \p{Control} U+0015 NEGATIVE ACKNOWLEDGE...is LEGAL in Java identifiers.
testing \p{Control} U+0016 SYNCHRONOUS IDLE...is LEGAL in Java identifiers.
testing \p{Control} U+0017 END OF TRANSMISSION BLOCK...is LEGAL in Java identifiers.
testing \p{Control} U+0018 CANCEL...is LEGAL in Java identifiers.
testing \p{Control} U+0019 END OF MEDIUM...is LEGAL in Java identifiers.
testing \p{Control} U+001A SUBSTITUTE...is LEGAL in Java identifiers.
testing \p{Control} U+001B ESCAPE...is LEGAL in Java identifiers.
testing \p{Control} U+001C INFORMATION SEPARATOR FOUR...is forbidden in Java identifiers.
testing \p{Control} U+001D INFORMATION SEPARATOR THREE...is forbidden in Java identifiers.
testing \p{Control} U+001E INFORMATION SEPARATOR TWO...is forbidden in Java identifiers.
testing \p{Control} U+001F INFORMATION SEPARATOR ONE...is forbidden in Java identifiers.
Legal but evil code points: U+0000 U+0001 U+0002 U+0003 U+0004 U+0005 U+0006 U+0007 U+0008 U+000E U+000F U+0010 U+0011 U+0012 U+0013 U+0014 U+0015 U+0016 U+0017 U+0018 U+0019 U+001A U+001B
그리고있다 :
$ perl test-java-idchars 0x600 0x700 | grep -i legal
testing \p{Control} U+0600 ARABIC NUMBER SIGN...is LEGAL in Java identifiers.
testing \p{Control} U+0601 ARABIC SIGN SANAH...is LEGAL in Java identifiers.
testing \p{Control} U+0602 ARABIC FOOTNOTE MARKER...is LEGAL in Java identifiers.
testing \p{Control} U+0603 ARABIC SIGN SAFHA...is LEGAL in Java identifiers.
testing \p{Control} U+06DD ARABIC END OF AYAH...is LEGAL in Java identifiers.
Legal but evil code points: U+0600 U+0601 U+0602 U+0603 U+06DD
다음 #!/usr/bin/env perl
#
# test-java-idchars - find which bogus code points Java allows in its identifiers
#
# usage: test-java-idchars [low high]
# e.g.: test-java-idchars 0 255
#
# Without arguments, tests Unicode code points
# from 0 .. 0x1000. You may go further with a
# higher explicit argument.
#
# Produces a report at the end.
#
# You can ^C it prematurely to end the program then
# and get a report of its progress up to that point.
#
# Tom Christiansen
# [email protected]
# Sat Jan 29 10:41:09 MST 2011
use strict;
use warnings;
use encoding "Latin1";
use open IO => ":utf8";
use charnames();
$| = 1;
my @legal;
my ($start, $stop) = (0, 0x1000);
if (@ARGV != 0) {
if (@ARGV == 1) {
for (($stop) = @ARGV) {
$_ = oct if /^0/; # support 0OCTAL, 0xHEX, 0bBINARY
}
}
elsif (@ARGV == 2) {
for (($start, $stop) = @ARGV) {
$_ = oct if /^0/;
}
}
else {
die "usage: $0 [ [start] stop ]\n";
}
}
for my $cp ($start .. $stop) {
my $char = chr($cp);
next if $char =~ /[\s\w]/;
my $type = "?";
for ($char) {
$type = "Letter" if /\pL/;
$type = "Mark" if /\pM/;
$type = "Number" if /\pN/;
$type = "Punctuation" if /\pP/;
$type = "Symbol" if /\pS/;
$type = "Separator" if /\pZ/;
$type = "Control" if /\pC/;
}
my $name = $cp ? (charnames::viacode($cp) || "<missing>") : "NULL";
next if $name eq "<missing>" && $cp > 0xFF;
my $msg = sprintf("U+%04X %s", $cp, $name);
print "testing \\p{$type} $msg...";
open(TESTPROGRAM, ">:utf8", "testchar.java") || die $!;
print TESTPROGRAM <<"End_of_Java_Program";
public class testchar {
public static void main(String argv[]) {
String var_$char = "variable name ends in $msg";
System.out.println(var_$char);
}
}
End_of_Java_Program
close(TESTPROGRAM) || die $!;
system q{
(javac -encoding UTF-8 testchar.java \
&& \
java -Dfile.encoding=UTF-8 testchar | grep variable \
) >/dev/null 2>&1
};
push @legal, sprintf("U+%04X", $cp) if $? == 0;
if ($? && $? < 128) {
print "<interrupted>\n";
exit; # from a ^C
}
printf "is %s in Java identifiers.\n",
($? == 0) ? uc "legal" : "forbidden";
}
END {
print "Legal but evil code points: @legal\n";
}
는도 공백이나 식별자 문자 단지 첫 33 개 코드 포인트에 그 프로그램을 실행하는 샘플입니다 질문
#!/usr/bin/env perl
#
# test-java-idchars - find which bogus code points Java allows in its identifiers
#
# usage: test-java-idchars [low high]
# e.g.: test-java-idchars 0 255
#
# Without arguments, tests Unicode code points
# from 0 .. 0x1000. You may go further with a
# higher explicit argument.
#
# Produces a report at the end.
#
# You can ^C it prematurely to end the program then
# and get a report of its progress up to that point.
#
# Tom Christiansen
# [email protected]
# Sat Jan 29 10:41:09 MST 2011
use strict;
use warnings;
use encoding "Latin1";
use open IO => ":utf8";
use charnames();
$| = 1;
my @legal;
my ($start, $stop) = (0, 0x1000);
if (@ARGV != 0) {
if (@ARGV == 1) {
for (($stop) = @ARGV) {
$_ = oct if /^0/; # support 0OCTAL, 0xHEX, 0bBINARY
}
}
elsif (@ARGV == 2) {
for (($start, $stop) = @ARGV) {
$_ = oct if /^0/;
}
}
else {
die "usage: $0 [ [start] stop ]\n";
}
}
for my $cp ($start .. $stop) {
my $char = chr($cp);
next if $char =~ /[\s\w]/;
my $type = "?";
for ($char) {
$type = "Letter" if /\pL/;
$type = "Mark" if /\pM/;
$type = "Number" if /\pN/;
$type = "Punctuation" if /\pP/;
$type = "Symbol" if /\pS/;
$type = "Separator" if /\pZ/;
$type = "Control" if /\pC/;
}
my $name = $cp ? (charnames::viacode($cp) || "<missing>") : "NULL";
next if $name eq "<missing>" && $cp > 0xFF;
my $msg = sprintf("U+%04X %s", $cp, $name);
print "testing \\p{$type} $msg...";
open(TESTPROGRAM, ">:utf8", "testchar.java") || die $!;
print TESTPROGRAM <<"End_of_Java_Program";
public class testchar {
public static void main(String argv[]) {
String var_$char = "variable name ends in $msg";
System.out.println(var_$char);
}
}
End_of_Java_Program
close(TESTPROGRAM) || die $!;
system q{
(javac -encoding UTF-8 testchar.java \
&& \
java -Dfile.encoding=UTF-8 testchar | grep variable \
) >/dev/null 2>&1
};
push @legal, sprintf("U+%04X", $cp) if $? == 0;
if ($? && $? < 128) {
print "<interrupted>\n";
exit; # from a ^C
}
printf "is %s in Java identifiers.\n",
($? == 0) ? uc "legal" : "forbidden";
}
END {
print "Legal but evil code points: @legal\n";
}
누구나이 미친듯한 행동을 설명 할 수 있습니까? U + 0000으로 시작하는 곳곳에 많은 다른 많은 불가사의하게 허용 된 코드 포인트가 있습니다. 이것은 아마도 모두 이상한 것입니다. 처음 0x1000 코드 포인트에서 실행하면 Current_Symbol
속성으로 모든 코드 포인트를 허용하는 것과 같은 특정 패턴이 나타납니다. 그러나 너무 많은 다른 것들은 적어도 저로서는 설명 할 수 없습니다.
사용중인 Java 언어 버전은 무엇입니까? IIRC 초기 버전은 "캐릭터가 몇 가지 특정 클래스 중 하나에 속하지 않으면 영숫자로 취급되고 식별자에 사용할 수 있습니다"라는 규칙을 가지고 있지만 이후 버전에서는 삭제 된 것으로 생각됩니다. – finnw
이것은 정말 짜증나며, 정말 좋은 질문입니다. 나는 또한 왜 그들이 국가적인 특성을 식별자에 허용하는지 알지 못한다. 중국 식별자를 사용하는 경우 소스가 어떻게 생겼는지 상상해보십시오. 또는 일본어. 또는 오른쪽에서 왼쪽으로 쓰여진 히브리어. C#에서도 마찬가지입니다. 제 동료 중 한 명이 실제로 러시아어 식별자를 사용합니다. 그것은 끔찍한 것처럼 보입니다. 종종 러시아어 (자국어 포함)에 대해서도 마찬가지입니다. –
@finnw : Java 버전 1.6입니다. – tchrist