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

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

2 अभ्यास

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

पृष्ठभूमि

स्ट्रिंग, कोट्स के बीच रखा गया टेक्स्ट होती है।

mystring <- "some text"
mystring
#> [1] "some text"
typeof(mystring)
#> [1] "character"

दुर्भाग्य से, दूसरी भाषाओं से परिचित प्रोग्रामरों को यह शब्दावली उलझा सकती है।

हालाँकि type character होता है, R एक अकेले अक्षर (जिसे कई दूसरी भाषाओं में char कहा जाता है, पर R में नहीं) और एक लंबी स्ट्रिंग में कोई फर्क नहीं करता। दोनों ही एक अकेली चीज़ हैं, और इन्हें सिंगल ' ' या डबल " " कोट्स में से किसी में भी, बराबर इस्तेमाल किया जा सकता है।

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

str2 <- 'String with "quotes"'  # convenience format
str2
#> [1] "String with \"quotes\""    # standard format

इस तरह एक character vector स्ट्रिंग्स का वेक्टर होता है, जिसमें हर स्ट्रिंग एक अलग एलिमेंट होती है।

s <- c("some", "strings")
s
#> [1] "some"    "strings"
length(s)
#> [1] 2
length(s[1])  # the number of vector elements, not the string length
#> [1] 1

nchar(s[1])  # the number of characters in the string "some"
#> [1] 4

ऊपर के उदाहरण में length(s[1]) और length("some") एक जैसे हैं: ये वेक्टर एलिमेंट की संख्या बताते हैं, स्ट्रिंग की लंबाई नहीं।

किसी एक स्ट्रिंग पर काम करना निश्चित रूप से संभव है, जैसे ऊपर के उदाहरण में nchar() से, लेकिन इसके लिए कुछ खास फंक्शन चाहिए, जिनकी चर्चा नीचे की जाएगी।

एस्केपिंग

जैसा हमने ऊपर देखा, कुछ विराम-चिह्नों के आगे बैकस्लैश \ लगाकर उन्हें "एस्केप" करना पड़ता है।

यह सूची ज़्यादातर अनुभवी प्रोग्रामरों के लिए कोई नई बात नहीं होगी, क्योंकि यह विषय लगभग सभी भाषाओं में एक जैसा मानकीकृत है।

कोट्स (जैसा ऊपर दिखाया गया) के अलावा, इस सूची में न्यूलाइन \n, टैब \t, बैकस्लैश \\, और \U या \u से शुरू होने वाले यूनिकोड चिह्न शामिल हैं।

बहुत सारे एस्केप कैरेक्टर इस्तेमाल करने से बचने के लिए, r"( )" के अंदर रॉ स्ट्रिंग बनाई जा सकती है:

r"(raw "string")"
#> [1] "raw \"string\""

जिन रॉ स्ट्रिंग में कोष्ठक ( ) हों, उनके लिए कई और सिंटैक्स विकल्प हैं।

लोकेल

R का हर समर्थित संस्करण स्ट्रिंग्स को UTF-8 में एन्कोड करता है, इसलिए दुनिया की ज़्यादातर भाषाएँ इस्तेमाल की जा सकती हैं।

"आधुनिक मानक हिन्दी"
#> [1] "आधुनिक मानक हिन्दी"

इसके अलावा, R के कई फंक्शन locale को पहचानते हैं और स्ट्रिंग की छँटाई, ऊपरी/निचली केस में बदलाव, तारीख और समय आदि के लिए स्थानीय तरीकों का पालन करने की कोशिश करते हैं।

यह सिलेबस ज़्यादातर अमेरिकी अंग्रेज़ी के उदाहरण दिखाएगा: एक तो यह आम डिफ़ॉल्ट है, और दूसरा इसलिए कि सिलेबस लिखने वाले खुद अमेरिका में रहते हैं।

लोकेल एक जटिल विषय है, इसलिए कृपया अपनी परिस्थिति के लिए दस्तावेज़ खुद खोजिए।

स्ट्रिंग फंक्शन

बेस R में ज़्यादातर चीज़ें संभव हैं, लेकिन बहुत से प्रोग्रामरों को स्ट्रिंग पर काम करने का सपोर्ट काफी सीमित और उलझा हुआ लगता है।

अच्छी बात यह है कि tidyverse के पैकेज मौजूद हैं, जो कहीं ज़्यादा सहज, लचीले और आपस में एक जैसे हैं।

बेस R

अभी भी बहुत सारा पुराना कोड है जो पुराने ढंग के स्ट्रिंग फंक्शन इस्तेमाल करता है। इसमें Exercism पर साझा किए गए ज़्यादातर हल शामिल हैं।

इसके अलावा, छोटे कामों के लिए बड़ी लाइब्रेरी आयात करने के बजाय बिल्ट-इन फंक्शन इस्तेमाल करना फायदेमंद हो सकता है। हमारे GitHub रेपो पर अभ्यासों को जाँचने के लिए आदर्श हल लिखते समय R ट्रैक के मेंटेनर आमतौर पर यही तरीका अपनाते हैं।

इसलिए पुराने तरीकों की थोड़ी जानकारी अब भी सीखने लायक है।

नीचे दिए गए फंक्शन अपने सबसे सरल रूप में बताए गए हैं, लेकिन ज़्यादातर में वैकल्पिक आर्गुमेंट भी होते हैं। विवरण के लिए दस्तावेज़ देखिए।

nchar

किसी स्ट्रिंग में अक्षरों की संख्या लौटाता है।

nchar("string")
#> [1] 6

nchar("Hrōðgār") # a person in Beowulf, written in Old English
#> [1] 7

यह (जटिल!) विषय कि "अक्षर" का मतलब क्या होता है, हमारे दायरे से बाहर है। ऊपर के उदाहरणों में बस कुछ बातें ध्यान में रखिए:

  • हालाँकि अंदर से ये C में लागू किए गए हैं, R की स्ट्रिंग्स \0 पर खत्म नहीं होतीं (जो लंबाई में 1 जोड़ देता)।
  • मल्टी-बाइट यूनिकोड अक्षरों को वैसे ही संभाला जाता है जैसी आप उम्मीद करेंगे। "Hrōðgār" में 7 अक्षर हैं (इन्हें "रून" या "कोड पॉइंट" भी कहते हैं), लेकिन इसे संग्रहीत करने के लिए 10 बाइट चाहिए।

nchar को क्या देते हैं, इसका ध्यान रखिए। गैर-character वैल्यू के लिए नतीजे अब भी अनिश्चित हो सकते हैं, हालाँकि R के हाल के संस्करणों में यह बेहतर हुआ है।

grep

स्ट्रिंग्स के एक वेक्टर में किसी पैटर्न को खोजता है और जहाँ-जहाँ मेल मिलता है उनके इंडेक्स लौटाता है।

grep("Jav", c("Java", "Python", "Javascript"))
#> [1] 1 3
paste और paste0

किसी भी संख्या की स्ट्रिंग्स को मिलाकर एक स्ट्रिंग बनाता है।

चाहें तो paste के लिए एक सेपरेटर तय कर सकते हैं: डिफ़ॉल्ट एक स्पेस है।

paste0(v) और paste(v, sep = "") एक जैसे हैं।

paste("bits", "of", "a", "string")
#> [1] "bits of a string"
paste0("bits", "of", "a", "string")
#> [1] "bitsofastring"
sprintf

स्ट्रिंग जोड़ने पर ज़्यादा बारीक नियंत्रण के लिए R ने sprintf फंक्शन C से लिया है (और बाद की कई भाषाओं से भी: विकिपीडिया इनकी सूची में लगभग 30 गिनाता है)।

r <- 5.3
pi <- 3.14159
sprintf("A circle of radius %.1f has area %.2f", r, pi * r^2)
#> [1] "A circle of radius 5.3 has area 88.25"
trimws

आगे और/या पीछे की खाली जगह trimws() से हटाई जा सकती है:

s <- "    messy string   "
trimws(s)
#> [1] "messy string"

दोनों सिरों को हटाने से बचने के लिए एक which = "left" (या "right") पैरामीटर होता है।

substr

एक अकेली स्ट्रिंग पर काम करता है और दो सीमाओं (दोनों को शामिल करते हुए) के बीच का सबस्ट्रिंग लौटाता है।

substr("Exercism", 5, 7)
#> [1] "cis"
strsplit

एक सेपरेटर स्ट्रिंग के आधार पर स्ट्रिंग को R की लिस्ट में बाँटता है। सेपरेटर देना ज़रूरी है (इसका कोई डिफ़ॉल्ट नहीं है), लेकिन यह खाली स्ट्रिंग भी हो सकता है।

strsplit("R, Python, Julia", ", ")
[[1]]
#> [1] "R"      "Python" "Julia" 

strsplit("Exercism", "")
[[1]]
#> [1] "E" "x" "e" "r" "c" "i" "s" "m"

लिस्ट की चर्चा एक अलग कॉन्सेप्ट में की जाएगी। अगर आप सिलेबस के उस हिस्से तक अभी नहीं पहुँचे हैं, तो फिलहाल इतना जान लीजिए कि unlist() फंक्शन (इस मामले में) एक लिस्ट को वेक्टर में बदल देता है।

unlist(strsplit("Exercism", ""))
#> [1] "E" "x" "e" "r" "c" "i" "s" "m"
regexpr और regexpr

"रेगुलर एक्सप्रेशन" का छोटा रूप। ये फंक्शन एक स्ट्रिंग में किसी पैटर्न की मौजूदगी खोजते हैं और (संभवतः) काम की जानकारी की एक लिस्ट लौटाते हैं। इनका ज़िक्र सिर्फ पूर्णता के लिए किया गया है: इनसे बेहतर विकल्प मौजूद हैं!

regexpr सिर्फ पहली मौजूदगी लौटाता है, gregexpr सारी मौजूदगियाँ लौटाता है ("g" का मतलब "global" खोज)।

जैसा नाम से पता चलता है, पैटर्न एक रेगेक्स हो सकता है, जिसकी चर्चा आगे के कॉन्सेप्ट में की जाएगी।

Advanced

ये पुराने स्ट्रिंग फंक्शन Unix शेल कमांड जैसे क्यों दिखते हैं?

R 1993 में बना था, फिर भी इसे S भाषा के साथ ज़्यादातर बैकवर्ड-कंपैटिबल बनाया गया था।

S को Bell Labs में बनाया गया था और यह पहली बार 1976 में सामने आई। Bell Labs ने Unix (1969 से) और C भाषा (1972) भी बनाई थी।

उस बहुत पुराने दौर की कमाल की टीम! हम बस यही मान सकते हैं कि उन सबने आपस में बात की और विचार साझा किए।

Tidyverse

अगर थोड़ा नरमी से कहें, तो पुराने ढंग के स्ट्रिंग फंक्शन वह सबसे अच्छा नहीं हैं जो R दे सकता है (इस पर कम नरम राय भी मिल सकती है)।

इसे बेहतर बनाने के लिए stringr लाइब्रेरी पर 2009 से काम चल रहा है, और अब यह Tidyverse संग्रह का अहम हिस्सा है।

इसे library(stringr) या library(tidyverse) से अपने नेमस्पेस में आयात कीजिए।

कुछ खास विशेषताएँ इस तरह हैं:

  • सभी फंक्शन के नाम पर str_ प्रीफ़िक्स लगता है और नाम से उद्देश्य साफ होने की कोशिश रहती है।
  • आर्गुमेंट का क्रम भी आपस में एक जैसा रखने की कोशिश होती है, जिसमें इनपुट डेटा पहला आर्गुमेंट होता है।
  • इनपुट एक अकेली स्ट्रिंग से लेकर जटिल डेटा ढाँचों तक कुछ भी हो सकता है। फंक्शन ढलने की कोशिश करते हैं और सबसे समझदारी वाला काम करते हैं।

Tidyverse के सभी पैकेजों की तरह stringr के दस्तावेज़ भी अच्छे हैं, जो आमतौर पर पैकेज के लेखकों ने लिखे होते हैं।

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

सोचिए कि आप क्या डालना चाहते हैं (एक अकेली स्ट्रिंग? वेक्टर? कुछ और जटिल?) और क्या निकालना चाहते हैं।

अगर आप सही फंक्शन और सही आर्गुमेंट ढूँढ लें, तो जो भी आप करना चाहते हैं उसका कोई आसान तरीका शायद मौजूद ही है।

विषयांतर: पाइप की छोटी-सी शुरुआत

फंक्शनों को जोड़ने के लिए पाइप |> के इस्तेमाल की चर्चा सिलेबस के दूसरे हिस्सों में और विस्तार से की जाएगी।

फिलहाल इतना जानना काम का है:

  • पाइप के बाईं ओर का नतीजा दाईं ओर के फंक्शन का पहला आर्गुमेंट बन जाता है (यहाँ "दाईं ओर" का मतलब है लाइन ब्रेक छोड़कर)।
  • बाकी बचे आर्गुमेंट फंक्शन कॉल में शामिल किए जा सकते हैं।
  • R में हमें पाइप किसी फंक्शन के कॉल तक ले जाना होता है, सिर्फ नाम तक नहीं, इसलिए ब्रैकेट हमेशा लगाने पड़ते हैं (कुछ और भाषाओं में ऐसा नहीं है)।

नीचे का उदाहरण सिंटैक्स दिखाता है। अलग-अलग फंक्शनों की चर्चा आगे की जाएगी।

library(stringr)

"Monday-25-February" |> 
  str_split("-") |>     
  unlist() |>               # [1] "Monday"   "25"       "February"
  str_sub(1, 3) |>          # [1] "Mon" "25"  "Feb"
  str_to_upper() |>         # [1] "MON" "25"  "FEB"
  str_flatten(collapse = ", ")
#> [1] "MON, 25, FEB"
लंबाई संभालिए

str_length कोड पॉइंट गिनता है (nchars जैसा)।

कई और फंक्शन खाली जगह पर काम करते हैं, जैसे str_trim() और str_squish()। किसी भी डेटा साइंस प्रोजेक्ट की शुरुआत में यह अक्सर एक ज़रूरी सफाई का काम होता है।

# The first 3 kernels in JuPyteR notebooks:
str_length(c("Julia", "Python", "R"))           #> [1] 1 6 5
#> [1] 5 6 1
str_pad(c("Julia", "Python", "R"), 8, "right")  # add spaces if necessary
#> [1] "Julia   " "Python  " "R       "

str_trim("Julia    Python    R    ")   # remove leading & trailing whitespace
#> [1] "Julia    Python    R"
str_squish("Julia   Python  R    ")  # trim, collapse multiple spaces 
#> [1] "Julia Python R"
स्ट्रिंग का हिस्सा निकालिए

str_sub(string, start, end) फंक्शन start से end तक (दोनों को शामिल करते हुए) सबस्ट्रिंग लौटाता है, जबकि str_sub_all() कई स्ट्रिंग्स पर काम कर सकता है।

इसमें बहुत लचीलापन है। start और end का डिफ़ॉल्ट क्रमशः पहला और अंतिम अक्षर होता है। ये इंडेक्स के वेक्टर भी हो सकते हैं। वेक्टर इंडेक्सिंग के उलट, जो अच्छी बात है, ऋणात्मक वैल्यू स्ट्रिंग के अंत से पीछे की ओर गिनती हैं, Python की तरह।

s <- "abcdefgh"
str_sub(s, 2, 4)
#> [1] "bcd"
str_sub(s, 5)
#> [1] "efgh"
str_sub(s, -3, -2)
#> [1] "fg"
str_sub(s, c(1, 4), c(2, 5))
#> [1] "ab" "de"
str_sub(s, c(1, 4, 6), c(2, 5, -1))
#> [1] "ab"  "de"  "fgh"

s |> str_sub(2, 4) # these functions are designed for pipes
#> [1] "bcd"

# str_sub_all takes vector input, gives list output
str_sub_all(c(s, "ijklmnop"), c(1, 4, 6), c(2, 5, -1))
[[1]]
#> [1] "ab"  "de"  "fgh"

[[2]]
#> [1] "ij"  "lm"  "nop"
स्ट्रिंग जोड़िए

str_flatten एक कैरेक्टर वेक्टर को अकेली स्ट्रिंग में बदलता है। collapse आर्गुमेंट हर एलिमेंट के बीच डाला जाता है और इसका डिफ़ॉल्ट "" है।

c("R", "Julia", "Python") |> str_flatten()
#> [1] "RJuliaPython"
c("R", "Julia", "Python") |> str_flatten(collapse = " - ")
#> [1] "R - Julia - Python"

str_c कई कैरेक्टर वेक्टर को एक कैरेक्टर वेक्टर में बदलता है, ज़रूरत के हिसाब से रीसाइक्लिंग के साथ।

str_c(LETTERS[1:8], 1:8, sep = ":")
#> [1] "A:1" "B:2" "C:3" "D:4" "E:5" "F:6" "G:7" "H:8"

str_glue R में सरल स्ट्रिंग इंटरपोलेशन लाता है। ब्रैसेज़ { } के अंदर के एक्सप्रेशन का मूल्यांकन किया जाता है और उनके टेक्स्ट रूप को वहाँ रख दिया जाता है।

अगर कई एक्सप्रेशन स्ट्रिंग दी जाएँ, तो वे भी str_flatten की तरह जोड़ दी जाती हैं। स्ट्रिंग के आगे और पीछे की खाली जगह को चाहें तो हटाया भी जा सकता है।

r <- 5.3
pi <- 3.14159
str_glue("A circle of radius {r} has area {pi * r^2}")
A circle of radius 5.3 has area 88.2472631

हालाँकि str_glue लचीला (और काफी जटिल) है, इसके पीछे की glue लाइब्रेरी में और भी ज़्यादा संभावनाएँ मौजूद हैं।

स्ट्रिंग बाँटिए

R का एक बहुत आम उपयोग है बिखरे डेटा को विश्लेषण के लिए एक जैसे प्रारूप में ढालना। इसमें मदद के लिए टेक्स्ट को सबस्ट्रिंग्स में बाँटने के कई तरीके हैं।

str_split_1 सबसे सरल है: यह एक अकेली स्ट्रिंग को टुकड़ों के वेक्टर में बदलता है, जिसे किसी तय पैटर्न पर बाँटा जाता है (इसका कोई डिफ़ॉल्ट पैटर्न नहीं है)।

s <- "R Julia Python"
str_split_1(s, " ")
#> [1] "R"      "Julia"  "Python"

str_split_i एक कैरेक्टर वेक्टर और एक इंडेक्स n लेता है, और हर इनपुट स्ट्रिंग के nवें सबस्ट्रिंग का एक वेक्टर लौटाता है।

s2 <- c(s, "C Kotlin, F#")  #> [1] "R Julia Python" "C Kotlin, F#"
str_split_i(s2, " ", 2)  # 2nd element of each
#> [1] "Julia"   "Kotlin,"

str_split एक कैरेक्टर वेक्टर लेता है और वेक्टरों की एक लिस्ट लौटाता है। हमारे सिलेबस में एक लिस्ट कॉन्सेप्ट है, जो इस आउटपुट को समझाता है।

str_split(s2, " ")
[[1]]
#> [1] "R"      "Julia"  "Python"

[[2]]
#> [1] "C"       "Kotlin," "F#"     

str_split_fixed भी है, जो एक मैट्रिक्स लौटाता है। मैट्रिक्स की चर्चा आगे के किसी कॉन्सेप्ट में की जाएगी।

स्ट्रिंग मिलाइए

पूरी स्ट्रिंग मिलाने के लिए str_equal() "समानता" की कई परिभाषाएँ इस्तेमाल कर सकता है। सबसे सरल रूप में डिफ़ॉल्ट केस-सेंसिटिव होता है, लेकिन इसे बदला जा सकता है। लोकेल और Unicode कई और संभावनाएँ खोल देते हैं।

str_equal("Odin", "odin")
#> [1] FALSE
str_equal("Odin", "odin", ignore_case = TRUE)
#> [1] TRUE

ऐसे कई और फंक्शन हैं, जिनकी चर्चा रेगुलर एक्सप्रेशन कॉन्सेप्ट में और विस्तार से की जाएगी।

स्ट्रिंग बदलिए

कुछ भाषाओं (मुख्यतः यूरोपीय) में बड़े और छोटे अक्षरों में फर्क किया जाता है। इन्हें लोकेल के हिसाब से एक-दूसरे में बदलने के लिए stringr में फंक्शनों का एक समूह है:

  • str_to_lower()
  • str_to_upper()
  • str_to_title() : हर शब्द का पहला अक्षर बड़ा
  • str_to_sentence() : वाक्य का पहला अक्षर बड़ा
str_to_upper("elixir")    # defaults to locale = "en"
#> [1] "ELIXIR"
str_to_upper("ελληνικά")  # infers Greek
#> [1] "ΕΛΛΗΝΙΚΆ"

str_to_title("the cat sat on the mat")
#> [1] "The Cat Sat On The Mat"
str_to_sentence("the cat sat on the mat")
#> [1] "The cat sat on the mat"

पैटर्न मिलान के आधार पर सबस्ट्रिंग बदलने के लिए str_replace() पैटर्न की पहली मौजूदगी बदलता है, और str_replace_all() सारी मौजूदगियाँ बदलता है।

अक्षर इंडेक्सिंग के आधार पर सबस्ट्रिंग बदलने के लिए str_sub() का एक असाइनमेंट रूप भी है।

 s <- "abcde"
str_sub(s, 3, 4) <- "yz"
s
#> [1] "abyze"
अन्य बातें

str_dup डुप्लिकेट बनाता है और str_unique डुप्लिकेट हटाता है।

डिफ़ॉल्ट रूप से str_dup में कोई सेपरेटर नहीं होता, लेकिन इसे तय किया जा सकता है।

str_dup("xyz", 4, sep = ", ")
#> [1] "xyz, xyz, xyz, xyz"

str_unique, unique() का ही एक विस्तार है। दोनों एक वेक्टर से डुप्लिकेट एंट्री हटाते हैं, लेकिन stringr वाला फंक्शन केस-सेंसिटिविटी और लोकेल-खास मिलान भी संभाल सकता है।

inp <- c("some", "strings", "Some", "Strings")
str_unique(inp)
#> [1] "some"    "strings" "Some"    "Strings"
str_unique(inp, ignore_case = TRUE)
#> [1] "some"    "strings"
Advanced

stringr लाइब्रेरी निचले स्तर के फंक्शनों वाली stringi लाइब्रेरी पर आधारित है।

अगर ऊपर बताई गई बातों के अलावा आपकी कोई खास ज़रूरत हो, तो:

  1. stringr का दस्तावेज़ देखिए, जिसमें इस इतने लंबे कॉन्सेप्ट दस्तावेज़ में बताए जा सकने वाले विकल्पों से भी ज़्यादा विकल्प हैं।
  2. stringi का दस्तावेज़ देखिए, जिसमें और भी बहुत सारी कार्यक्षमता का वर्णन है।
GitHub के ज़रिए संपादित करें यह लिंक नई विंडो या टैब में खुलता है।

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

अभ्यास लॉक है

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