यह कोड, पीछे की ओर लिखा हुआ, "हैलो वर्ल्ड!"


261

यहाँ कुछ कोड है जो मुझे इंटरनेट पर मिले हैं:

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

यह कोड Hello World!स्क्रीन पर प्रिंट करता है; आप इसे यहां चला सकते हैं । मैं स्पष्ट रूप से public static void mainलिखित देख सकता हूं , लेकिन यह पीछे की ओर है। यह कोड कैसे काम करता है? यह कैसे भी संकलित करता है?

संपादित करें: मैंने IntellIJ में इस कोड की कोशिश की, और यह ठीक काम करता है। हालांकि, किसी कारण से यह cmd के साथ, नोटपैड ++ में काम नहीं करता है। मुझे अभी भी इसका कोई हल नहीं मिला है, इसलिए यदि कोई करता है, तो नीचे टिप्पणी करें।


38
यह एक अजीब है ... RTL समर्थन के साथ कुछ भी करना है?
यूजीन श।

12
यूनिकोड वर्ण # 8237 है; इसके ठीक बाद Mऔर इसके बाद भी []a: fileformat.info/info/unicode/char/202d/index.htm इसे LEFT-TO-RIGHT OVERRIDE कहा जाता है
17'17 को रिवाइज करें

45
अनिवार्य xkcd: xkcd.com/1137
Pac0

4
आप अपने माउस का उपयोग करके कोड स्निपेट में चयन करके आसानी से देख सकते हैं कि यहां क्या हो रहा है।
एंड्रियास रिजेब्रांड

14
niam diov citats cilbupएक लैटिन कहावत की तरह लगता है ..
मिक Mnemonic

जवाबों:


250

यहां अदृश्य अक्षर हैं जो कोड को प्रदर्शित करने के तरीके को बदलते हैं। Intellij में इन्हें कोड को एक खाली स्ट्रिंग ( "") में कॉपी-पेस्ट करके पाया जा सकता है , जो उन्हें यूनिकोड के साथ बदल देता है, उनके प्रभावों को हटा देता है और संकलक के आदेश को प्रकट करता है।

यहाँ उस कॉपी-पेस्ट का आउटपुट दिया गया है:

"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','!'});}}   "

स्रोत कोड वर्ण इस क्रम में संग्रहीत किए जाते हैं, और संकलक उन्हें इस क्रम में होने के रूप में मानते हैं, लेकिन वे अलग तरह से प्रदर्शित होते हैं।

\u202Eवर्ण पर ध्यान दें , जो दाएं-से-बाएं ओवरराइड है, एक ऐसा ब्लॉक शुरू करना जहां सभी वर्णों को दाएं-से-बाएं प्रदर्शित होने के लिए मजबूर किया जाता है, और \u202D, जो बाएं से दाएं ओवरराइड है, एक नेस्ट ब्लॉक को शुरू करना जहां सभी पहले ओवरराइड को ओवरराइड करके पात्रों को बाएं से दाएं क्रम में मजबूर किया जाता है।

इरगो, जब यह मूल कोड प्रदर्शित करता है, तो class Mसामान्य रूप से प्रदर्शित होता है, लेकिन \u202Eवहां से सब कुछ के प्रदर्शन क्रम को \u202Dउलट देता है, जो फिर से सब कुछ उलट देता है। (औपचारिक रूप से, \u202Dलाइन टर्मिनेटर से सब कुछ दो बार उल्टा हो जाता है, एक बार कारण से \u202Dऔर एक बार बाकी पाठ के कारण उलट जाता है \u202E, यही कारण है कि यह पाठ अंत के बजाय लाइन के बीच में दिखाई देता है।) अगली पंक्ति की दिशात्मकता को पहली बार लाइन टर्मिनेटर के कारण स्वतंत्र रूप से नियंत्रित किया जाता है, इसलिए {'H','e','l','l','o',' ','W','o','r','l','d','!'});}}इसे सामान्य रूप से प्रदर्शित किया जाता है।

पूर्ण (अत्यंत जटिल, दर्जनों पृष्ठों लंबा) यूनिकोड द्विदिश एल्गोरिथ्म के लिए, यूनिकोड मानक अनुलग्नक # 9 देखें


आप यह नहीं समझाते हैं कि संकलक (प्रदर्शन दिनचर्या के विपरीत) उन यूनिकोड पात्रों के साथ स्वयं क्या करता है। मैं उन्हें एकमुश्त अनदेखा कर सकता हूं (या उन्हें श्वेत-स्थान के रूप में मान सकता हूं), या यह उनकी व्याख्या कर सकता है कि वास्तव में स्रोत कोड में योगदान दे रहा है। मुझे यहां जावा नियमों का पता नहीं है, लेकिन तथ्य यह है कि वे अन्यथा अप्रयुक्त पहचानकर्ताओं के अंत में रखे जाते हैं, मुझे पता चलता है कि यह बाद का हो सकता है, और यूनिकोड अक्षर वास्तव में उन पहचानकर्ता नामों का हिस्सा हैं।
मार्क वैन लीउवेन

क्या यह सी # में उसी तरह से काम करेगा, ब्याज से बाहर?
IanF1

14
@ IanF1 यह किसी भी भाषा में काम करेगा जहां संकलक / दुभाषिया RTL और LTR वर्णों को व्हाट्सएप के रूप में गिना जाता है। लेकिन उत्पादन कोड में ऐसा कभी न करें यदि आप अपने कोड को छूने के लिए अगले व्यक्ति की पवित्रता को महत्व देते हैं, जो कि आप हो सकते हैं।
wizzwizz4

2
या, दूसरे शब्दों में: "हमेशा कोड के रूप में अगर आपके कोड को बनाए रखने वाला व्यक्ति एक हिंसक मनोरोगी है जो जानता है कि वह कहां रहता है।" , @ IanF1। या शायद: "हमेशा कोड के रूप में अगर आपके कोड को बनाए रखने वाले व्यक्ति का नाम होगा और आपको स्टैक ओवरफ्लो पर मूल लेखक के रूप में शर्मिंदा करना होगा।"
कोड़ी ग्रे

43

यह यूनिकोड बिडायरेक्शनल एल्गोरिथम के कारण अलग दिखता है । आरएलओ और एलआरओ के दो अदृश्य पात्र हैं जो यूनिकोड बिडायरेक्शनल अल्गोरिद्म का उपयोग इन दोनों मेटाचैकर्स के बीच के पात्रों के दृश्य स्वरूप को बदलने के लिए करते हैं ।

इसका परिणाम यह होता है कि नेत्रहीन वे उल्टे क्रम में दिखते हैं, लेकिन स्मृति में वास्तविक वर्ण उलट नहीं होते हैं। आप यहां परिणामों का विश्लेषण कर सकते हैं । जावा कंपाइलर आरएलओ और एलआरओ को नजरअंदाज करेगा, और उन्हें व्हाट्सएप के रूप में व्यवहार करेगा, यही कारण है कि कोड संकलित करता है।

नोट 1: यह एल्गोरिथ्म पाठ संपादकों और ब्राउज़रों द्वारा एलटीआर अक्षर (अंग्रेजी) और आरटीएल अक्षर (जैसे अरबी, हिब्रू) दोनों को एक ही समय में एक साथ प्रदर्शित करने के लिए उपयोग किया जाता है - इसलिए "द्वि-असीमित"। आप यूनिकोड की वेबसाइट पर Bidirectional Algorithm के बारे में अधिक पढ़ सकते हैं ।
नोट 2: एलआरओ और आरएलओ के सटीक व्यवहार को एल्गोरिथम की धारा 2.2 में परिभाषित किया गया है ।


ऐसी क्षमता का उद्देश्य क्या है?
यूजीन श।

6
अरबी और हिब्रू को सही ढंग से प्रस्तुत करने के लिए कभी-कभी इन पात्रों की आवश्यकता होती है। इन भाषाओं को राइट-टू-लेफ्ट (RTL) पढ़ा और लिखा जाता है , पहला कैरेक्टर जो पढ़ा / लिखा जाता है वह राइट-हैंड साइड पर दिखाई देता है । आप यहां और पढ़ सकते हैं ।
जेम्स लॉसन

अरबी और हिब्रू अक्षर आंतरिक रूप से RTL हैं, हालांकि - वे स्पष्ट ओवरराइड के बिना भी RTL दिखाई देंगे, और वे पास के कुछ अन्य वर्णों के क्रम को स्वचालित रूप से उलट देंगे, मुझे लगता है कि ज्यादातर विराम चिह्न - इसलिए स्पष्ट ओवरराइड शायद ही कभी आवश्यक होते हैं।
user2357112 मोनिका का

यह पृष्ठ यहाँ बताता है कि ओवरराइड्स कब आवश्यक हैं। @ user2357112 सही है, वे शायद ही कभी जरूरत हो। वास्तव में जब आपके पास विराम चिह्न, उद्धरण और संख्या होती है - इन विशेष वर्णों को "तटस्थ" माना जाता है। ऐसे कंप्यूटर के लिए जो शब्दों को नहीं पढ़ सकता है और संदर्भ को समझ नहीं सकता है, यह स्पष्ट नहीं है कि उन्हें LTR या RTL के रूप में माना जाए, लेकिन बीड़ी एल्गोरिथम को कुछ ऑर्डर देना होगा। कभी-कभी यह "गलत हो जाता है" और आपको इन ओवरराइड पात्रों का उपयोग "सही करने" के लिए करना होगा।
जेम्स लॉसन

3
इसके अलावा, U + 202E और U + 202D को व्हॉट्सएप नहीं माना जाता है। Java केवल ASCII स्पेस, हॉरिजॉन्टल टैब, फॉर्म फीड और CR / LF / CRLF को व्हॉट्सएप मानता है । वे वास्तव में पहचानकर्ताओं का शाब्दिक हिस्सा हैं M\u202Eऔर a\u202D, लेकिन उन पहचानकर्ताओं को Mऔर के बराबर माना जाता है a। (जेएलएस यह समझाने का अच्छा काम नहीं करता है।)
user2357112

28

चरित्र U+202Eदाएं से बाएं तक कोड को दर्पण करता है, हालांकि यह बहुत चालाक है। M में छिपा हुआ है,

"class M\u202E{..."

मैंने इसके पीछे जादू कैसे पाया ?

ठीक है, पहली बार में जब मैंने सवाल देखा था कि मैं सख्त हूं, "यह एक तरह का मजाक है, किसी और को खोने के लिए", लेकिन फिर, मैंने अपना आईडीई ("इंटेलीज") खोला, एक वर्ग बनाएं, और कोड को पिछले ... और यह संकलित !!! तो, मैंने एक बेहतर रूप लिया और देखा कि "सार्वजनिक स्थैतिक शून्य" पिछड़ा हुआ था, इसलिए मैं कर्सर के साथ वहां गया, और कुछ वर्ण मिटा दिए ... और क्या होता है? वर्ण पीछे हटने लगे , इसलिए, मैंने सोचा कि एमएमएम .... दुर्लभ ... मुझे इसे निष्पादित करना होगा ... इसलिए मैं कार्यक्रम को निष्पादित करने के लिए आगे बढ़ता हूं, लेकिन पहले मुझे इसे बचाने की जरूरत थी ... और वह तब था जब मैं मिल गया! । मैं फ़ाइल को सहेज नहीं सका क्योंकि मेरी आईडीई ने कहा कि कुछ चार के लिए एक अलग एन्कोडिंग थी, और मुझे इंगित करें कि यह कहाँ था, इसलिए मैं Google में विशेष चर के लिए एक शोध शुरू करता हूं जो काम कर सकता है, और वह यह है :)

थोड़ा सा

यूनिकोड द्विदिश एल्गोरिथ्म, और U+202Eशामिल, एक संक्षिप्त व्याख्या :

यूनिकोड स्टैंडर्ड एक मेमोरी प्रतिनिधित्व आदेश को तार्किक क्रम के रूप में जाना जाता है। जब पाठ क्षैतिज रेखाओं में प्रस्तुत किया जाता है, तो अधिकांश स्क्रिप्ट बाएं से दाएं वर्ण प्रदर्शित करती हैं। हालाँकि, कई लिपियाँ हैं (जैसे कि अरबी या हिब्रू) जहाँ प्रदर्शन में क्षैतिज पाठ का प्राकृतिक क्रम दाएँ से बाएँ होता है। यदि सभी पाठ में एक समान क्षैतिज दिशा है, तो प्रदर्शन पाठ का क्रम अस्पष्ट है।

हालाँकि, क्योंकि ये दाएँ-से-बाएँ स्क्रिप्ट अंकों का उपयोग करते हैं जो बाएँ से दाएँ लिखे जाते हैं, पाठ वास्तव में द्वि-दिशात्मक होता है: दाएँ से बाएँ और बाएँ से दाएँ पाठ का मिश्रण। अंकों के अलावा, अंग्रेजी और अन्य लिपियों से एम्बेडेड शब्द भी बाएं से दाएं लिखे जाते हैं, साथ ही द्विदिश पाठ का उत्पादन भी करते हैं। एक स्पष्ट विनिर्देश के बिना, अस्पष्टता प्रदर्शित वर्णों के क्रम को निर्धारित करने में उत्पन्न हो सकती है जब पाठ की क्षैतिज दिशा एक समान नहीं होती है।

यह अनुलग्नक द्विदिश यूनिकोड पाठ के लिए दिशा निर्धारित करने के लिए उपयोग किए जाने वाले एल्गोरिदम का वर्णन करता है। एल्गोरिथ्म वर्तमान में कई मौजूदा कार्यान्वयनों द्वारा नियोजित निहित मॉडल का विस्तार करता है और विशेष परिस्थितियों के लिए स्पष्ट स्वरूपण वर्ण जोड़ता है। ज्यादातर मामलों में, सही प्रदर्शन आदेश प्राप्त करने के लिए पाठ के साथ अतिरिक्त जानकारी शामिल करने की आवश्यकता नहीं है।

हालाँकि, बिडायरेक्शनल टेक्स्ट के मामले में, ऐसी परिस्थितियाँ होती हैं जहाँ एक अंतर्निहित बिडायरेक्शनल ऑर्डर कॉम्प्रिहेंसिव टेक्स्ट का उत्पादन करने के लिए पर्याप्त नहीं होता है। इन मामलों से निपटने के लिए, जब प्रस्तुत किया जाता है तो पात्रों के क्रम को नियंत्रित करने के लिए दिशात्मक स्वरूपण वर्णों का एक न्यूनतम सेट परिभाषित किया जाता है। यह सुव्यवस्थित इंटरचेंज के लिए डिस्प्ले ऑर्डरिंग के सटीक नियंत्रण की अनुमति देता है और यह सुनिश्चित करता है कि फ़ाइलनाम या लेबल जैसी सरल वस्तुओं के लिए उपयोग किए जाने वाले सादे पाठ को हमेशा प्रदर्शन के लिए सही ढंग से ऑर्डर किया जा सकता है।

इस तरह से कुछ एल्गोरिथ्म क्यों बनाएं ?

बीड़ी एल्गोरिथ्म एक के बाद एक बाएं से दाएं अरबी या हिब्रू वर्णों के अनुक्रम को प्रस्तुत कर सकता है।


4

भाषा विनिर्देश के अध्याय 3 में एक जावा प्रोग्राम के लिए शाब्दिक अनुवाद कैसे किया जाता है, इस बारे में विस्तार से वर्णन करके एक विवरण प्रदान करता है। सवाल के लिए क्या मायने रखता है:

कार्यक्रम यूनिकोड (§3.1) में लिखे गए हैं , लेकिन लेक्सिकल अनुवाद प्रदान किए गए हैं (.23.2) ताकि यूनिकोड बच (.33.3) का उपयोग केवल ASCII वर्णों का उपयोग करके किसी भी यूनिकोड वर्ण को शामिल करने के लिए किया जा सके।

तो एक कार्यक्रम यूनिकोड वर्णों में लिखा गया है, और लेखक उनका उपयोग करके बच सकता है \uxxxx फाइल एन्कोडिंग का समर्थन नहीं करने की स्थिति में यूनिकोड वर्ण का समर्थन नहीं करता है, इस स्थिति में यह उपयुक्त वर्ण में अनुवादित होता है। इस मामले में मौजूद यूनिकोड वर्णों में से एक है \u202E। यह स्निपेट में नेत्रहीन नहीं दिखाया गया है, लेकिन यदि आप ब्राउज़र के एन्कोडिंग को बदलने की कोशिश करते हैं, तो छिपे हुए अक्षर दिखाई दे सकते हैं।

इसलिए, शाब्दिक अनुवाद कक्षा घोषणा में परिणाम करता है:

class M\u202E{

जिसका अर्थ है कि वर्ग पहचानकर्ता है M\u202Eविनिर्देश एक वैध पहचानकर्ता के रूप में इस पर विचार करता है:

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

एक "जावा पत्र-या-अंक" एक ऐसा चरित्र है जिसके लिए यह विधि Character.isJavaIdentifierPart(int)सही है।


क्षमा करें, लेकिन यह पिछड़ा हुआ है (यमक इच्छित)। स्रोत कोड में कोई पलायन नहीं हैं; आप बता रहे हैं कि यह कैसे लिखा जा सकता था। और, यह "एम" (सिर्फ एक चरित्र) नामक एक वर्ग के लिए संकलित करता है।
टॉम ब्लोडेट

@TomBlodget वास्तव में लेकिन बिंदु (जो वास्तव में मैंने कल्पना उद्धरण में उजागर किया है) यह है कि संकलक कच्चे यूनिकोड वर्णों को भी संसाधित कर सकता है। यह वास्तव में पूरी व्याख्या है। भागने का अनुवाद केवल एक अतिरिक्त जानकारी है और सीधे इस मामले से संबंधित नहीं है। संकलित वर्ग के लिए, मुझे लगता है कि यह इसलिए है क्योंकि आरटीएल स्विच चरित्र किसी तरह संकलक द्वारा खारिज किया जा रहा है। मैं यह देखने की कोशिश करूंगा कि क्या यह अपेक्षित है, लेकिन मुझे लगता है कि शाब्दिक अनुवाद चरण के बाद होता है।
एम अनूटी
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.