जूलिया में String अक्षरों का एक क्रमबद्ध अनुक्रम होता है। जैसा कि मैनुअल कहता है: "बेशक, असली परेशानी तब शुरू होती है जब कोई पूछे कि अक्षर क्या होता है।"
इस जटिलता का अधिक विस्तार से वर्णन Chars कॉन्सेप्ट में किया जाएगा, लेकिन संक्षेप में:
सामान्य तौर पर स्ट्रिंग को दोहरे उद्धरण चिह्न " " में बंद किया जाता है।
एकल उद्धरण चिह्न ' ' केवल Chars के लिए इस्तेमाल होते हैं।
ट्रिपल डबल-कोट्स """ """ का इस्तेमाल भी किया जा सकता है, जिससे स्ट्रिंग के अंदर " बिना एस्केप किए इस्तेमाल किया जा सकता है।
और भी ज़रूरी, मल्टीलाइन स्ट्रिंग से अनचाही अतिरिक्त इंडेंटेशन हटा दी जाती है।
julia> """
Multiline
"""
"Multiline\nString\n"
C से शुरू होने वाली ज़्यादातर भाषाओं की तरह, जूलिया एस्केपिंग के लिए बैकस्लैश \ का इस्तेमाल करती है:
\n।\$ (नीचे देखिए)।सिद्धांत रूप में, स्ट्रिंग को वेक्टर की तरह ही इंडेक्स किया जा सकता है:
julia> s[1], s[5]
('J', 'a')
यह "Julia" जैसी ASCII स्ट्रिंग के लिए साफ़ तौर पर काम करता है, लेकिन दुनिया की ज़्यादातर भाषाओं को यह नज़रअंदाज़ करता है।
Beowulf के एक अक्षर पर विचार कीजिए, जो करीब 15 शताब्दियों पहले पुरानी अंग्रेज़ी में लिखा गया था।
"Hrōðgār" साफ़ तौर पर 7 अक्षरों का है, लेकिन उनमें से सभी ASCII नहीं हैं।
julia> king = "Hrōðgār"
"Hrōðgār"
julia> length(king)
7
julia> isascii(king)
false
# collect() converts to a Char vector:
julia> collect(king)
7-element Vector{Char}:
'H': ASCII/Unicode U+0048 (category Lu: Letter, uppercase)
'r': ASCII/Unicode U+0072 (category Ll: Letter, lowercase)
'ō': Unicode U+014D (category Ll: Letter, lowercase)
'ð': Unicode U+00F0 (category Ll: Letter, lowercase)
'g': ASCII/Unicode U+0067 (category Ll: Letter, lowercase)
'ā': Unicode U+0101 (category Ll: Letter, lowercase)
'r': ASCII/Unicode U+0072 (category Ll: Letter, lowercase)
ऐसी स्ट्रिंग में इंडेक्स करना शुरू में ठीक चलता है, लेकिन किसी मोड़ पर टूट जाता है:
julia> king[3]
'ō': Unicode U+014D (category Ll: Letter, lowercase)
julia> king[4]
ERROR: StringIndexError: invalid index [4], valid nearby indices [3]=>'ō', [5]=>'ð'
समस्या यह है कि इस तरह इंडेक्स करना बाइट गिनता है, और गैर-ASCII स्ट्रिंग में बाइट का अक्षरों से 1:1 संबंध नहीं होता।
एक यूनिकोड/UTF-8 अक्षर को दिखाने के लिए 4 बाइट तक लग सकते हैं, और Chars कॉन्सेप्ट इस पर और आगे चर्चा करेगा।
कई भाषाएँ स्ट्रिंग कॉन्कैटिनेशन ऑपरेटर के तौर पर + इस्तेमाल करती हैं, लेकिन जूलिया नहीं करती।
कम से कम एरर का संदेश तो मददगार है।
julia> "s1 " + "s2"
ERROR: MethodError: no method matching +(::String, ::String)
The function `+` exists, but no method is defined for this combination of argument types.
String concatenation is performed with *
julia> "s1 " * "s2"
"s1 s2"
string() फंक्शन किसी भी संख्या में स्ट्रिंग जोड़ सकता है।
julia> string("lots ", "of ", "bits")
"lots of bits"
join() फंक्शन भी यही करता है, और स्ट्रिंग के वेक्टर लेकर उन्हें दिए गए सेपरेटर से जोड़ सकता है (डिफ़ॉल्ट "" होता है)।
julia> join(["lots", "of", "bits"], "_")
"lots_of_bits"
ध्यान दीजिए कि स्ट्रिंग अपरिवर्तनीय होती हैं, और कॉन्कैटिनेशन में कॉपी करना शामिल होता है। इसलिए लूप के अंदर बार-बार कॉन्कैटिनेशन करना बेकर होता है, और बेहतर है कि टुकड़ों को एक वेक्टर में इकट्ठा करें और अंत में सबको जोड़ दें।
सरल:
julia> repeat("Abc", 5)
"AbcAbcAbcAbcAbc"
कई भाषाओं में स्ट्रिंग के अंदर गणना की गई वैल्यू डालने का तरीका होता है, हालाँकि सबसे अच्छा सिंटैक्स क्या हो, इस पर बहुत मतभेद है।
जूलिया में इंटरपोलेट की गई वैल्यू से पहले $ आता है।
julia> myvar = 42
42
julia> "myvar evaluates to $myvar"
"myvar evaluates to 42"
julia> r = 5.3
5.3
julia> "A circle of radius $r has area $(π * r^2)"
"A circle of radius 5.3 has area 88.24733763933729"
जब कोष्ठक हटाने से अस्पष्टता हो सकती हो तो कोष्ठक ज़रूरी होते हैं, लेकिन किसी अकेले आइडेंटिफायर के बाद व्हाइटस्पेस हो तो वे वैकल्पिक होते हैं।
स्ट्रिंग में $ शामिल करने के लिए उसे \$ की तरह एस्केप कीजिए।
ध्यान दीजिए कि इंटरपोलेशन में फिलहाल फॉर्मेटिंग की सुविधा नहीं है, जैसे दिखाने के लिए दशमलव स्थानों की संख्या तय करना।
@sprintf()स्ट्रिंग जोड़ने पर ज़्यादा बारीक नियंत्रण के लिए, जूलिया ने C से sprintf फंक्शन की नकल की है (और बाद की कई भाषाओं से भी: विकिपीडिया पर करीब 30 भाषाएँ सूचीबद्ध हैं)।
जूलिया में इसे Printf मॉड्यूल के अंदर एक macro के तौर पर लागू किया गया है, इसलिए @ प्रीफ़िक्स लगता है।
julia> using Printf
julia> r = 5.3
5.3
julia> @sprintf("A circle of radius %.1f has area %.2f", r, π * r^2)
"A circle of radius 5.3 has area 88.25"
सरलता के लिए, यह खंड उन फंक्शन पर ध्यान देगा जो नई स्ट्रिंग लौटाते हैं और इनपुट को बदले बिना छोड़ देते हैं।
कई फंक्शन के ऐसे समकक्ष होते हैं जिनके नाम के अंत में ! लगा होता है, और जो इनपुट को मौके पर ही बदल देते हैं।
स्ट्रिंग कितनी लंबी है? कभी-कभी यह इस पर निर्भर करता है कि आप कैसे गिन रहे हैं।
सरल मामला ASCII स्ट्रिंग का है, जिसमें हर अक्षर 1 बाइट जगह लेता है।
julia> string_asc = "Julia"
"Julia"
julia> length(string_asc)
5
julia> sizeof(string_asc)
5
length() फंक्शन अक्षरों की संख्या लौटाता है, और sizeof() फंक्शन बाइट की संख्या लौटाता है।
दूसरे अक्षर-समूहों के साथ यह अंतर अहम हो जाता है:
julia> king = "Hrōðgār"
"Hrōðgār"
julia> length(king)
7
julia> sizeof(king)
10
प्रोग्रामिंग में एक आम काम है किसी लंबी स्ट्रिंग को लेकर उसे एक या अधिक अक्षरों वाली सेपरेटर स्ट्रिंग के आधार पर टुकड़ों में तोड़ना।
आम तौर पर हम split() फंक्शन इस्तेमाल करते हैं।
सेपरेटर का डिफ़ॉल्ट (कोई भी) व्हाइटस्पेस होता है, लेकिन दूसरे भी तय किए जा सकते हैं।
julia> split("my little string")
3-element Vector{SubString{String}}:
"my"
"little"
"string"
julia> split("My_snake_case_string", "_")
4-element Vector{SubString{String}}:
"My"
"snake"
"case"
"string"
ये उदाहरण एक स्ट्रिंग को छोटी स्ट्रिंग में तोड़ते हैं। किसी स्ट्रिंग को अक्षरों में तोड़ना अलग काम है।
क्या किसी स्ट्रिंग में कोई तय सबस्ट्रिंग मौजूद है?
अजीब बात है, इसे जाँचने के लिए दो फंक्शन हैं: occursin() और contains() केवल अपने आर्गुमेंट के क्रम में अलग हैं।
julia> needle = "Julia"
"Julia"
julia> haystack = "Python, Julia and R"
"Python, Julia and R"
julia> occursin(needle, haystack)
true
julia> contains(haystack, needle)
true
स्थिति के बारे में ज़्यादा स्पष्ट होने के लिए:
julia> startswith(haystack, "Python")
true
julia> endswith(haystack, "Python")
false
किसी सबस्ट्रिंग के start:end इंडेक्स पाने के लिए हमारे पास कई फंक्शन हैं:
findfirst()findlast()findprev()findnext()julia> findfirst(needle, haystack)
9:13
सबस्ट्रिंग बदलने के लिए, x => y सिंटैक्स का इस्तेमाल करके बदलावों की सूची बनाइए।
julia> replace("abc", "a"=>"b", "b"=>"c", "c"=>"a")
"bca"
जूलिया 1.7 से, replace फंक्शन किसी भी संख्या में बदलाव ले सकता है, इस गारंटी के साथ कि बदलने के दौरान किसी अक्षर को एक से ज़्यादा बार नहीं बदला जाएगा।
x => y सिंटैक्स को pair कहा जाता है, जो जूलिया में एक अहम टाइप है और जिसके बारे में ज़्यादा जानकारी Dicts and Pairs कॉन्सेप्ट में दी गई है।
हमें अक्सर किसी स्ट्रिंग से शुरू और/या अंत का व्हाइटस्पेस हटाना पड़ता है।
इसके लिए फंक्शन हैं lstrip() (बाएँ), rstrip() (दाएँ), strip() (दोनों)।
julia> strip("\n\t useful_bit\n\n")
"useful_bit"
इन फंक्शन के नाम काफी हद तक खुद अपना मतलब बता देते हैं:
julia> s = repeat("aBcD ", 5)
"aBcD aBcD aBcD aBcD aBcD "
julia> uppercase(s)
"ABCD ABCD ABCD ABCD ABCD "
julia> lowercase(s)
"abcd abcd abcd abcd abcd "
julia> titlecase(s) # Initial letter of each word uppercase
"Abcd Abcd Abcd Abcd Abcd "
इस अभ्यास में आप लॉग लाइनों पर काम करेंगे।
हर लॉग लाइन इस तरह बनी एक स्ट्रिंग होती है: "[<LEVEL>]: <MESSAGE>"।
लॉग लेवल तीन तरह के होते हैं:
INFOWARNINGERRORआपके पास तीन काम हैं, और हर काम में एक लॉग लाइन दी जाएगी जिस पर आपको कुछ करना होगा।
लॉग लाइन का मैसेज लौटाने के लिए message फंक्शन बनाइए:
julia> message("[ERROR]: Invalid operation")
"Invalid operation"
आगे या पीछे की कोई भी खाली जगह हटा दी जानी चाहिए:
julia> message("[WARNING]: Disk almost full\r\n")
"Disk almost full"
लॉग लाइन का लॉग लेवल लौटाने के लिए log_level फंक्शन बनाइए। यह लेवल छोटे अक्षरों में लौटाया जाना चाहिए:
julia> log_level("[ERROR]: Invalid operation")
"error"
reformat फंक्शन बनाइए, जो लॉग लाइन का प्रारूप बदल देता है। इसमें मैसेज पहले आता है और उसके बाद कोष्ठकों में लॉग लेवल:
julia> reformat("[INFO]: Operation completed")
"Operation completed (info)"
ध्यान दें: इस अभ्यास की सभी स्ट्रिंग अंग्रेज़ी में हैं और सिर्फ ASCII अक्षरों तक सीमित हैं। आगे के कॉन्सेप्ट में आपको Unicode अक्षरों के साथ काम करने का मौका मिलेगा।
Exercism पर साइन अप कीजिए और Julia को 35 कॉन्सेप्ट128 अभ्यास तथा असली इंसानों से मिलने वाली मेंटरिंग के साथ सीखिए और उसमें महारत हासिल कीजिए, वह भी बिल्कुल मुफ्त।