ट्रैक
/
Julia
Julia
/
सिलेबस
/
स्ट्रिंग
स्

स्ट्रिंग में Julia

7 अभ्यास

स्ट्रिंग के बारे में

जूलिया में String अक्षरों का एक क्रमबद्ध अनुक्रम है। जैसा कि मैनुअल कहता है: "सच्ची मुश्किल तब शुरू होती है जब कोई पूछे कि अक्षर है क्या।"

इस पूरी जटिलता पर Chars कॉन्सेप्ट में और विस्तार से बात होगी, पर संक्षेप में:

  • जूलिया में सभी स्ट्रिंग्स Unicode होती हैं।
  • जो स्ट्रिंग्स ASCII भी हैं (अंग्रेज़ी के A से Z तक के बड़े और छोटे अक्षर, अंक और कुछ विराम चिह्न), उनके साथ काम करना आसान है।
  • दुनिया की बाकी ज़्यादातर लेखन प्रणालियों के साथ काम करना संभव है, पर उनमें ज़्यादा ध्यान देना पड़ता है।

स्ट्रिंग लिटरल

आम तौर पर स्ट्रिंग्स दोहरे उद्धरण चिह्नों " " में बंद की जाती हैं। एकल उद्धरण चिह्न ' ' सिर्फ Chars के लिए इस्तेमाल होते हैं।

तीन दोहरे उद्धरण चिह्नों """ """ का उपयोग भी किया जा सकता है, जिनसे स्ट्रिंग के अंदर " को बिना एस्केप किए लिखा जा सकता है। और इससे भी ज़रूरी बात, कई पंक्तियों वाली स्ट्रिंग्स से अनचाहा अतिरिक्त इंडेंटेशन हटा दिया जाता है।

julia> """
       Multiline
       String
       """
"Multiline\nString\n"

अक्षरों को एस्केप करना

C से आगे की ज़्यादातर भाषाओं की तरह जूलिया भी एस्केप करने के लिए बैकस्लैश \ का उपयोग करती है:

  1. ऐसे अक्षर लिखने के लिए जो छपते नहीं, जैसे पिछले उदाहरण में नई पंक्ति \n।
  2. ऐसे अक्षरों को बचाने के लिए जिनका वरना कोई खास अर्थ होता, जैसे \$ (नीचे देखिए)।

इटरेशन

स्ट्रिंग एक ऐसा संग्रह है जिस पर इटरेशन किया जा सकता है, इसलिए for ... in लूप बिना अक्षरों के वेक्टर में बदले सीधे चल जाता है।

julia> s = "Julia"
"Julia"

# admittedly, this is a silly example
julia> for c in s; print(c, "; "); end
J; u; l; i; a; 

इस तरह इटरेशन करने का फ़ायदा यह है कि जूलिया अक्षरों की सीमाओं को ठीक से सँभाल लेती है, ऐसी स्ट्रिंग्स में भी जो ASCII नहीं हैं। ऐसा क्यों मायने रखता है, यह अगले भाग में और साफ़ हो जाएगा।

इंडेक्सिंग

सिद्धांत रूप में, स्ट्रिंग्स पर वेक्टर की तरह ही इंडेक्सिंग की जा सकती है:

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 संबंध नहीं होता। एक Unicode/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"

जब ब्रैकेट हटाने से अर्थ अस्पष्ट हो जाए तो वे ज़रूरी हैं, पर अगर सिर्फ एक आइडेंटिफ़ायर हो और उसके बाद स्पेस हो, तो वे वैकल्पिक होते हैं।

स्ट्रिंग में $ लिखने के लिए उसे \$ की तरह एस्केप कीजिए।

ध्यान दीजिए कि फ़िलहाल इंटरपोलेशन में फ़ॉर्मैटिंग की सुविधा नहीं है, जैसे कि कितने दशमलव स्थान दिखाए जाएँ।

इससे निपटने के तरीके ये हैं:

  • गणना को round() फंक्शन में लपेट दीजिए।
  • Exercism टेस्ट रनर के बाहर PyFormattedStrings पैकेज Python की f-strings की नकल करता है।
  • @sprintf() मैक्रो के बारे में नीचे बताया गया है।

@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"

ये उदाहरण एक स्ट्रिंग को छोटी स्ट्रिंग्स में तोड़ते हैं। स्ट्रिंग को अक्षरों में तोड़ना एक अलग काम है।

julia> collect("input string")
12-element Vector{Char}:
 'i': ASCII/Unicode U+0069 (category Ll: Letter, lowercase)
 'n': ASCII/Unicode U+006E (category Ll: Letter, lowercase)
 'p': ASCII/Unicode U+0070 (category Ll: Letter, lowercase)
 'u': ASCII/Unicode U+0075 (category Ll: Letter, lowercase)
 't': ASCII/Unicode U+0074 (category Ll: Letter, lowercase)
 ' ': ASCII/Unicode U+0020 (category Zs: Separator, space)
 's': ASCII/Unicode U+0073 (category Ll: Letter, lowercase)
 't': ASCII/Unicode U+0074 (category Ll: Letter, lowercase)
 'r': ASCII/Unicode U+0072 (category Ll: Letter, lowercase)
 'i': ASCII/Unicode U+0069 (category Ll: Letter, lowercase)
 'n': ASCII/Unicode U+006E (category Ll: Letter, lowercase)
 'g': ASCII/Unicode U+0067 (category Ll: Letter, lowercase)

ढूँढना और बदलना

क्या किसी स्ट्रिंग में कोई दिया हुआ सबस्ट्रिंग है? अजीब बात है कि यह जाँचने के लिए दो फंक्शन हैं: 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

किसी सबस्ट्रिंग के शुरू से अंत तक के इंडेक्स पाने के लिए हमारे पास कई फंक्शन हैं:

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 "

पार्सिंग

संख्याओं को स्ट्रिंग में और स्ट्रिंग को संख्या में बदलना अक्सर काम आता है।

संख्या को स्ट्रिंग में बदलना आसान है, हालाँकि डिफ़ॉल्ट 10 के अलावा कोई और बेस देना हो तो एक अतिरिक्त पैरामीटर चाहिए:

julia> string(42)
"42"

julia> string(42, base=16)
"2a"

julia> string(42, base=2)
"101010"

स्ट्रिंग को पार्स करके कोई संख्यात्मक वैल्यू पाना थोड़ा ज़्यादा पेचीदा है, और इसमें गलती होने के मौके भी ज़्यादा हैं। लक्ष्य संख्या टाइप बताना ज़रूरी है। बेस बताना वैकल्पिक है और उसका डिफ़ॉल्ट 10 है।

julia> parse(Int, "42")
42

julia> parse(Float64, "42")
42.0

julia> parse(Int, "42?")
ERROR: ArgumentError: invalid base 10 digit '?' in "42?"

julia> parse(Int, "42 ")  # whitespace may be tolerated
42

खास स्ट्रिंग्स

कभी-कभी स्ट्रिंग्स के अंदर सामान्य इंटरपोलेशन और एस्केपिंग बंद कर देना काम आता है। इसके लिए शुरुआती उद्धरण चिह्न से पहले raw लगा दीजिए।

julia> x = 10
10

julia> "x = $x if we use \$ for interpolation"
"x = 10 if we use \$ for interpolation"

julia> raw"x = $x if we use \$ for interpolation"
"x = \$x if we use \\\$ for interpolation"

रेगुलर एक्सप्रेशन का अपना पेचीदा सिंटैक्स होता है, और जूलिया दो काम के स्ट्रिंग टाइप देता है: Regex के लिए r" " और कैप्चर किए गए टुकड़ों पर काम करने के लिए s" "।

बाकी कई खास स्ट्रिंग्स Exercism जैसी प्रोग्रामिंग में कम दिखती हैं, पर लाइब्रेरी बनाने में खूब इस्तेमाल होती हैं।

  • सेमांटिक वर्ज़न स्ट्रिंग्स v"x.y.z" सॉफ़्टवेयर रिलीज़ की major.minor.patch संख्या सँभालती हैं।
  • बाइट ऐरे लिटरल b" " Unicode की अक्षर-सीमाओं को दरकिनार कर देते हैं और बाइट के स्तर पर काम करते हैं।
GitHub के ज़रिए संपादित करें यह लिंक नई विंडो या टैब में खुलता है।

स्ट्रिंग सीखिए

अभ्यास लॉक है

स्ट्रिंग पर अभ्यास करने के लिए 2 और अभ्यास अनलॉक कीजिए