Geriye yazılan bu kod neden “Merhaba Dünya!”


261

İşte internette bulduğum bazı kodlar:

class M‮{public static void main(String[]a‭){System.out.print(new char[]
{'H','e','l','l','o',' ','W','o','r','l','d','!'});}}    

Bu kod ekrana yazdırılır Hello World!; burada çalıştığını görebilirsiniz . public static void mainYazılı olduğunu açıkça görebiliyorum , ama geriye doğru. Bu kod nasıl çalışır? Bu nasıl derleniyor?

Düzenleme: IntellIJ bu kodu denedim ve iyi çalışıyor. Ancak, bazı nedenlerden dolayı cmd ile birlikte notepad ++ ile çalışmaz. Buna hala bir çözüm bulamadım, bu yüzden eğer birisi yaparsa, aşağıya yorum yapın.


38
Bu komik ... RTL desteği ile ilgili bir şey var mı?
Eugene Sh.

12
Unicode karakteri var # 8237; hemen sonra Mve sonra []a: fileformat.info/info/unicode/char/202d/index.htm Buna SOL-TO-SAĞ OVERRIDE denir
Riiverside

45
zorunlu xkcd: xkcd.com/1137
Pac0

4
Farenizi kullanarak kod snippet'inde seçimler yaparak burada neler olduğunu kolayca görebilirsiniz.
Andreas Rejbrand

14
niam diov citats cilbupLatin atasözü gibi geliyor ..
Mick Mnemonic

Yanıtlar:


250

Kodun görüntülenme şeklini değiştiren görünmez karakterler var. Intellij'de bunlar, kodu ""Unicode kaçışlarıyla değiştiren boş bir dizeye ( ) kopyalayıp yapıştırarak, etkilerini kaldırarak ve derleyicinin gördüğü sırayı ortaya çıkararak bulunabilir.

İşte bu kopyala-yapıştırın çıktısı:

"class M\u202E{public static void main(String[]a\u202D){System.out.print(new char[]\n"+
        "{'H','e','l','l','o',' ','W','o','r','l','d','!'});}}   "

Kaynak kod karakterleri bu sırayla saklanır ve derleyici bu sıraya göre davranır, ancak farklı şekilde görüntülenir.

Not \u202Etüm karakterlerin sağdan sola-görüntülenecek zorunda kalan bir blok başlayarak sağdan sola geçersiz kılma olan karakteri, ve \u202Dbir soldan-sağa geçersiz kılma olduğunu, iç içe geçmiş bir blok nerede tüm başlangıç karakterler soldan sağa doğru zorlanarak ilk geçersiz kılmayı geçersiz kılar.

Ergo, orijinal kodu class Mgörüntülediğinde normal olarak görüntülenir, ancak \u202Eher şeyin görüntülenme sırasını oradan 'e \u202Dtersine çevirir, bu da her şeyi tekrar tersine çevirir. (Biçimsel \u202Dolarak, satır sonlandırıcıdan her şeye bir kez \u202Dve iki kez tersine çevrilmiş metnin geri kalanı nedeniyle iki kez tersine çevrilir \u202E, bu nedenle bu metin satır yerine satırın ortasında görünür.) Sonraki satırın yönü, hat sonlandırıcısı nedeniyle birincisinden bağımsız olarak ele alınır, bu nedenle {'H','e','l','l','o',' ','W','o','r','l','d','!'});}}normal olarak görüntülenir.

Tam (son derece karmaşık, düzinelerce sayfa uzunluğunda) Unicode çift yönlü algoritma için bkz. Unicode Standart Ek # 9 .


Derleyicinin (ekran yordamının aksine) bu Unicode karakterlerinin kendileri ile ne yaptığını açıklamıyorsunuz. Onları açıkça görmezden gelebilirim (veya beyaz boşluk olarak kabul edebilirim) veya onları kaynak koduna katkıda bulunduğu şeklinde yorumlayabilirim. Burada Java kurallarını bilmiyorum, ancak aksi takdirde kullanılmayan tanımlayıcıların sonuna yerleştirildikleri gerçeği bana ikincisi olabileceğini ve Unicode karakterlerinin aslında bu tanımlayıcı adlarının bir parçası olduğunu gösteriyor.
Marc van Leeuwen

Bu ilgi c #, aynı şekilde çalışır mı?
IanF1

14
@ IanF1 Derleyicinin / yorumlayıcının RTL ve LTR karakterlerini boşluk olarak saydığı herhangi bir dilde çalışır. Ancak , kodunuza dokunacak bir sonraki kişinin akıl sağlığına değer veriyorsanız, bunu asla üretim kodunda yapmayın , ki bu sizin de iyi olabilir.
wizzwizz4

2
Veya başka bir deyişle: "Her zaman kodunuzu koruyan kişi, nerede yaşadığınızı bilen şiddetli bir psikopat gibi kodlayın." , @ IanF1. Veya belki: "Her zaman kodunuzu koruyan kişi sizi Stack Overflow'daki orijinal yazar olarak adlandırır ve utandırır."
Cody Gray

43

Unicode Çift Yönlü Algoritma nedeniyle farklı görünüyor . Unicode Çift Yönlü Algoritmanın bu iki metakarakter arasında yuvalanmış karakterlerin görsel görünümünü değiştirmek için kullandığı görünmez iki RLO ve LRO karakteri vardır.

Sonuç olarak görsel olarak ters sırada görünürler, ancak bellekteki gerçek karakterler tersine çevrilmez. Sonuçları burada analiz edebilirsiniz . Java derleyicisi RLO ve LRO'yu yok sayar ve bunları boşluk olarak kabul eder, bu yüzden kod derlenir.

Not 1: Bu algoritma, metin editörleri ve tarayıcıları tarafından hem LTR karakterlerini (İngilizce) hem de RTL karakterlerini (ör. Arapça, İbranice) birlikte aynı anda görsel olarak görüntülemek için kullanılır - bu nedenle "bi" yönlü. İki Yönlü Algoritma hakkında Unicode'un web sitesinde daha fazla bilgi bulabilirsiniz .
Not 2: LRO ve RLO'nun tam davranışı Algoritmanın Bölüm 2.2'sinde tanımlanmıştır .


Böyle bir yeteneğin amacı nedir?
Eugene Sh.

6
Arapça ve İbranice görsel olarak doğru bir şekilde oluşturmak için bazen bu karakterlere ihtiyaç vardır. Bu diller sağdan sola (RTL) okunur ve yazılır , okunan / yazılan ilk karakter sağ tarafta görünür . Daha fazlasını buradan okuyabilirsiniz .
James Lawson

Arapça ve İbranice karakterler aslında RTL'dir - açık bir geçersiz kılma olmadan bile RTL görünecekler ve hatta yakındaki diğer karakterlerin sırasını otomatik olarak tersine çevirecekler, bence çoğunlukla noktalama işaretleri - bu yüzden açık geçersiz kılmalar nadiren gerekli.
user2357112

Bu sayfa burada geçersiz kılar gerekli olduğunda açıklar. @ user2357112 doğru, nadiren ihtiyaç duyuluyor. Aslında noktalama işaretleri, alıntılar ve sayılar olduğunda - bu özel karakterler "tarafsız" olarak kabul edilir. Kelimeleri okuyamayan ve bağlamı anlayamayan bir bilgisayar için, bunları LTR veya RTL olarak ele alıp almayacağınız belirsizdir, ancak bidi algoritması bazı siparişleri seçmek zorundadır . Bazen "yanlış anlar" ve "geçersiz kılmak" için bu geçersiz kılma karakterlerini kullanmanız gerekir.
James Lawson

3
Ayrıca, U + 202E ve U + 202D boşluk sayılmaz. Java yalnızca ASCII alanı, yatay sekme, form beslemesi ve CR / LF / CRLF'yi boşluk olarak kabul eder . Onlar lexically aslında tanımlayıcıları parçasıyız M\u202Eve a\u202Dfakat bu tanımlayıcılar için aynı şekilde ele alınacak görünmektedir Mve a. (JLS bunu açıklamak için iyi bir iş
çıkarmaz

28

Karakter U+202Ekodu sağdan sola yansıtır, ancak çok zekidir. M'den başlayarak gizlidir,

"class M\u202E{..."

Bunun arkasındaki büyüyü nasıl buldum ?

İlk başta sert olduğum soruyu gördüğümde, "başka bir zaman kaybetmek bir tür şaka", ama sonra IDE'mi ("IntelliJ") açtım, bir sınıf yarattım ve kodu geçtim ... ve derlendi !!! Daha iyi baktım ve "genel statik boşluğun" geri olduğunu gördüm, o yüzden imleçle oraya gittim, ve birkaç karakter sildim ... Ve ne olacak? Karakterler geriye doğru silmeye başladı , bu yüzden mmm ... nadir ... yürütmek zorundayım ... Programı yürütmeye devam ediyorum, ama önce kaydetmem gerekiyordu ... ve o zaman buldum! . Dosyayı kaydedemedim çünkü IDE'm bazı karakter için farklı bir kodlama olduğunu söyledi ve bana nerede olduğunu işaret etti, Bu yüzden Google'da işi yapabilen özel karakterler için bir araştırma başlattım ve hepsi bu kadar :)

Hakkında biraz

Unicode Çift Yönlü Algoritma ve U+202Eilgili kısaca şunları açıklar :

Unicode Standardı, mantıksal düzen olarak bilinen bir bellek temsil sırası belirler. Metin yatay çizgiler halinde sunulduğunda, çoğu komut dosyası karakterleri soldan sağa görüntüler. Bununla birlikte, ekrandaki yatay metnin doğal sırasının sağdan sola olduğu birkaç komut dosyası (Arapça veya İbranice gibi) vardır. Metnin tümünün düzgün bir yatay yönü varsa, görüntüleme metninin sırası net değildir.

Ancak, bu sağdan sola komut dosyaları soldan sağa yazılan rakamları kullandığından, metin aslında iki yönlüdür: sağdan sola ve soldan sağa metnin karışımı. Rakamlara ek olarak, İngilizce ve diğer komut dosyalarından gelen gömülü kelimeler de soldan sağa yazılır ve ayrıca çift yönlü metin üretir. Net bir şartname olmadan, metnin yatay yönü tekdüze olmadığında görüntülenen karakterlerin sırasını belirlerken belirsizlikler ortaya çıkabilir.

Bu ek, çift yönlü Unicode metnin yönünü belirlemek için kullanılan algoritmayı açıklar. Algoritma, halihazırda mevcut bir dizi uygulama tarafından kullanılan örtük modeli genişletmekte ve özel durumlar için açık biçimlendirme karakterleri eklemektedir. Çoğu durumda, doğru görüntü sırasını elde etmek için metne ek bilgi eklemenize gerek yoktur.

Ancak, çift yönlü metin söz konusu olduğunda, anlaşılır metin üretmek için örtük bir çift yönlü sıralamanın yeterli olmadığı durumlar vardır. Bu durumlarla başa çıkmak için, oluşturulduğunda karakterlerin sırasını kontrol etmek için minimal bir yönlü biçimlendirme karakter kümesi tanımlanır. Bu, okunaklı değişim için ekran sırasının tam kontrolüne izin verir ve dosya adları veya etiketler gibi basit öğeler için kullanılan düz metnin her zaman görüntüleme için doğru şekilde sipariş edilmesini sağlar.

Neden gibi bazı algoritma oluşturmak bu ?

bidi algoritması, Arapça veya İbranice karakter dizisini sağdan sola arka arkaya oluşturabilir.


4

Dil spesifikasyonunun 3. Bölümü , bir Java programı için sözcüksel çevirinin nasıl yapıldığını ayrıntılı olarak açıklayarak bir açıklama sağlar. Soru için en önemli şey:

Programlar Unicode'da (§3.1) yazılmıştır , ancak sözcüksel çeviriler (§3.2) sağlanır, böylece Unicode çıkışları (§3.3) yalnızca ASCII karakterleri kullanan herhangi bir Unicode karakterini içermek için kullanılabilir.

Bu nedenle bir program Unicode karakterlerle yazılır \uxxxxve dosya kodlamasının Unicode karakterini desteklememesi durumunda yazar bunları kullanarak kaçabilir , bu durumda uygun karaktere çevrilir. Bu durumda bulunan Unicode karakterlerinden biri \u202E. Snippet'te görsel olarak gösterilmez, ancak tarayıcının kodlamasını değiştirmeyi denerseniz gizli karakterler görünebilir.

Bu nedenle, sözcüksel çeviri sınıf bildirimiyle sonuçlanır:

class M\u202E{

yani sınıf tanımlayıcısıdır M\u202E. Şartname geçerli bir tanıtıcısında olarak kabul etti:

Identifier:
    IdentifierChars but not a Keyword or BooleanLiteral or NullLiteral
IdentifierChars:
    JavaLetter {JavaLetterOrDigit}

"Java harf veya rakamı", yöntemin Character.isJavaIdentifierPart(int)true değerini döndürdüğü bir karakterdir .


Üzgünüm ama bu geri döndü (kelime oyunu). Kaynak kodda çıkış yok; nasıl yazıldığını açıklıyorsunuz. Ve "M" (sadece bir karakter) adlı bir sınıfa derlenir.
Tom Blodget

@TomBlodget Gerçekten ama nokta (aslında spec alıntı vurgulanan) derleyici de ham Unicode karakterleri işleyebilir olmasıdır. Gerçekten bütün açıklama bu. Kaçış çevirisi yalnızca ek bir bilgidir ve doğrudan bu durumla ilgili değildir. Derlenmiş sınıfa gelince, bunun nedeni RTL anahtar karakterinin bir şekilde derleyici tarafından atılmasıdır. Bunun beklenip beklenmediğini görmeye çalışacağım, ancak sözcüksel çeviri aşamasından sonra olduğunu düşünüyorum.
M Anouti
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.