क्या आपको Base64 फ़ॉर्मेट के साथ काम करना होता है? तो यह साइट आपके लिए एकदम सही है! अपने डेटा को एन्कोड या डिकोड करने के लिए, हमारे बेहद आसान ऑनलाइन टूल का इस्तेमाल करें।

R में Base64 डिकोडिंग: एक सम्पूर्ण गाइड

आपकी R सेशन में एक स्ट्रिंग उतर आती है। वह एक हिला-मिलाए वर्णमाला के सूप जैसी लगती है: अक्षर, अंक, कभी-कभार एक प्लस या स्लैश, और पूंछ पर लटकी एक जोड़ी बराबर चिह्नों। जिसे भेजा है वह क़सम खाता है कि यह कभी एक बिल्कुल साधारण वाक्य था, एक JPEG, या एक JSON दस्तावेज़। वही स्ट्रिंग Base64 है, और यह पेज उसी को वापस उस चीज़ में बदलने की रेसिपी है जो वह पहले था।

एक तेज़ दोहराई, क्योंकि इस साइट का होम पेज इस फ़ॉर्मैट को पूरा-पूरा गहराई से समझाता है: Base64 तीन इनपुट बाइट्स को 64 चिह्नों की वर्णमाला से लिए चार चरों के रूप में लिखता है, और पूंछ में एक या दो = चर बताते हैं कि असली डेटा कहाँ ख़त्म हुआ। वही चार-बदल-तीन सौदा है जिसकी वजह से एन्कोडेड टेक्स्ट मूल की तुलना में करीब एक-तिहाई बड़ा होता है, और डिकोडिंग बस उसी सौदे को उल्टा चलाती है। सवाल का स्वरूप दिमाग में रखिए और चलिए कुछ एन्वेलॉप खोलते हैं।

यही वह मोड़ है जो R को कई अन्य भाषाओं से थोड़ा अलग बनाता है: बेस R में Base64 की बात ही नहीं है। किसी बेस पैकेज में छिपा कोई base64_decode() नहीं है, न कोई वन-लाइन बिल्टइन जिसका सहारा लिया जा सके। आपको एक पैकेज लाना ही होगा। अच्छी खबर यह है कि एकोसिस्टम में ऐसे कई पैकेज उपलब्ध हैं, हर एक की अपनी शख़्सियत, और इस लेख के अंत तक आपको ठीक-ठीक पता हो जाएगा कि किसका सहारा लें और किस पर भरोसा न करें।

डिकोडर एक नज़र में

भारी-भरकाना काम पाँच पैकेज करते हैं, और वे दो बड़े दलों में बँट जाते हैं: दयालु, जो गंदे इनपुट पर सिर हिला देते हैं, और सख़्त, जो RFC को एक करार की तरह लेते हैं। यहाँ है पूरा दल, 2026 के हिसाब से ताज़ा:

पैकेज वर्ज़न (2026) डिकोड एंट्री पॉइंट शख़्सियत
base64enc 0.1-6 base64decode() डिफ़ॉल्ट रूप से दयालु, फ़रवरी 2026 में strict मोड जुड़ा
openssl 2.4.2 base64_decode() व्हाइटस्पेस छोड़ देता है, लेकिन चुपचाप फ़ेल होने के ऐसे रास्ते हैं जिन पर सख़्त नज़र से देखना ज़रूरी है
b64 0.1.7 decode(), decode_as_string() सख़्त, वेक्टराइज़्ड, Rust में लिखा, तेज़
base64 2.0.2 decode() openssl के ऊपर फ़ाइल-से-फ़ाइल सुविधा वाला रैपर
base64url 1.4 base64_urldecode() URL-सुरक्षित वर्णमाला, कोई पैडिंग नहीं, चुपचाप माफ़ कर देने वाला

तीन रनर-अप का ज़िक्र ज़रूरी है। jsonlite पैकेज अपने खुद के हेल्पर एक्सपोर्ट करता है, base64_enc, base64_dec और URL-सुरक्षित जोड़ी, इसलिए अगर आप पहले से JSON पार्स करते हैं, तो शायद आपके पास पहले से एक डिकोडर टँगा हो। jose पैकेज JWT काम के लिए base64url_decode() के साथ आता है। और बहुत पुराना RCurl पैकेज आज भी base64() फ़ंक्शन साथ रखता है जो libcurl को रैप करता है: यह चलता है, यह चर-ओरिएंटेड है, और यह नए कोड का औज़ार नहीं, बल्कि एक वफ़ादार दादा जैसा लगता है।

दल को इंस्टॉल करना

अगर मशीन पर अभी R नहीं है, तो आपका ऑपरेटिंग सिस्टम इसे साथ देता है: Debian और Ubuntu पर r-base, Fedora पर R, macOS और Windows पर एक पैकेज या इंस्टॉलर। फिर पैकेज, सीधे CRAN से:

install.packages("base64enc")
install.packages("openssl")
install.packages("b64")
install.packages("base64url")

दो बिल्ड नोट्स, क्योंकि इंस्टॉल की गड़बड़ियाँ यहीं पर होती हैं। openssl पैकेज आपके सिस्टम OpenSSL के ख़िलाफ़ कंपाइल होता है, इसलिए साफ़ Linux बॉक्स को पहले डेवलपमेंट हेडर्स चाहिए होंगे:

sudo apt install libssl-dev

b64 पैकेज extendr से रैप किया गया Rust इंजन है, इसलिए सोर्स से बिल्ड करने के लिए Rust टूलचैन की ज़रूरत है (sudo apt install cargo के साथ rustc भी आ जाती है)। Windows और macOS पर CRAN से प्री-बिल्ट बायनेरी मिलती हैं और इसमें से कुछ भी लागू नहीं होता। अगर आप पैकेज मैनेजर पसंद करते हैं, तो pak::pkg("base64enc") या remotes::install_cran("b64") रिपॉजिटरी पर कम राय के साथ वही काम करते हैं।

आपका पहला डिकोड: तीन पंक्तियों की रस्म

डिकोडिंग की ज़िंदगी का नब्बे प्रतिशत तीन पंक्तियों में समा जाता है। यहाँ है मानक स्मोक टेस्ट, मशहूर TWFu स्ट्रिंग से:

library(base64enc)
packed <- "TWFu"
bytes <- base64decode(packed)
bytes
#> [1] 4d 61 6e
rawToChar(bytes)
#> [1] "Man"

उस छोटी सी रस्म में तीन बातें नोट करने लायक हैं। पहली, base64decode() हमेशा आपको raw वेक्टर सौंपता है, कभी स्ट्रिंग नहीं। यह एक फीचर है, ग़लती नहीं: Base64 एक वाक्य, JPEG, या सर्टिफ़िकेट सब ला सकता है, और यह पता चलने से पहले कि आपके पास क्या है, इनमें से किसी को भी अलग-तरह से नहीं समझना चाहिए। दूसरी, बाइट्स से वापस टेक्स्ट की छलांग एक अलग, जान-बूझ कर लिया गया कदम है, rawToChar() के रास्ते, और बस उसी कदम पर कैरेक्टर सेट का फैसला बसता है (उसके बारे में बाद में)। तीसरी, TWFu शब्द "Man" में डिकोड होता है: तीन अक्षर, ज़ीरो खटके। वह स्ट्रिंग अपनी जेब में रखिए। अगर कोई डिकोड कोड TWFu को Man में बदल दे, तो मशीन ईमानदार है।

क्योंकि आप आख़िरकार हमेशा कुछ ऐसा डिकोड करेंगे जो आपने खुद एन्कोड किया था, यहाँ है पूरा राउंड ट्रिप जो साबित करता है कि दोनों दिशाएँ एकमत हैं:

text <- "Hello, world!"
packed <- base64encode(charToRaw(text))
packed
#> [1] "SGVsbG8sIHdvcmxkIQ=="
identical(text, rawToChar(base64decode(packed)))
#> [1] TRUE

raw वेक्टर की सीमा

R बाइट/टेक्स्ट की सीमा पार करता है दो छोटे फ़ंक्शनों के साथ, और एक बार जब आप उन्हें जान लेंगे तो इस लेख की बाक़ी चीज़ें अपने-आप सही लगने लगेंगी। charToRaw() स्ट्रिंग को उसके बाइट्स में बदलता है, rawToChar() उल्टा काम करता है, और बीच में आपके पास पूरा raw टूलकिट है: बाइट्स गिनने के लिए length(), झाँकने के लिए head(), और फ़ाइलों के बीच उन्हें आना-जाना करने के लिए writeBin() और readBin()। इस लेख का हर एक डिकोडर जान-बूझ कर उसी सीमा पर रुक जाता है।

bytes <- base64decode("SGVsbG8s")
length(bytes)
#> [1] 6
head(bytes)
#> [1] 48 65 6c 6c 6f 2c
rawToChar(bytes)
#> [1] "Hello,"

तो जब आपको [1] 48 जैसे रिज़ल्ट दिखें, उसे "एक बाइट, मान 72, अक्षर H" के रूप में पढ़िए, और वहीं रुक जाइए जब तक आपको न पता चले कि बाइट्स किस कैरेक्टर सेट में लिपटे हैं। वही रुकावट ही डिकोडिंग की पूरी अनुशासन है।

गंदा इनपुट: डिकोडर कहाँ पर एकमत नहीं हैं

यही वह सेक्शन है जो दो बजे रात को आपकी जान बचाएगा, क्योंकि इनपुट थोड़ा सा गंदा होने पर क्या होता है, इसमें डिकोडर एकमत नहीं हैं। असल दुनिया का Base64 अंदर-अंदर स्पेस के साथ आता है, घबराए हुए कॉपी-पेस्ट से गिर चुकी पैडिंग के साथ, एक ऐसे चिह्न के साथ, जिसे क्लिपबोर्ड ने निगल लिया हो, या पूंछ में टँगे कचरे के साथ। यहाँ हर डिकोडर का जवाब है, उसी परिवार के दोषियों पर:

इनपुट base64enc (डिफ़ॉल्ट) base64enc (strict = TRUE) openssl b64
"SGVs bG8s IHdvcmxkIQ==" (बीच में एक स्पेस) "Hello, world!" (स्पेस छोड़ा गया) एरर: ग़लत चर, जगह दी गई "Hello, world!" (स्पेस छोड़ा गया) एरर
"SGVsbG8sIHdvcmxkIQ" (पैडिंग गिर गई) "Hello, world!" (मिसिंग पैडिंग सह गई) एरर: पैडिंग मिसिंग एरर: डिकोड फ़ेल एरर: ग़लत पैडिंग
"SGVsbG8s!IHdvcmxkIQ==" (बीच में एक "!") "Hello, world!" (ग़लत चर छोड़ा गया) एरर: ग़लत चर ख़ाली raw वेक्टर, कोई एरर नहीं एरर
"SGVsbG8sIHdvcmxkIQ==xx" (पूंछ में कचरा) "Hello, world!" (कचरा अनदेखा) एरर: पूंछ वाला कंटेंट ख़ाली raw वेक्टर, कोई एरर नहीं एरर
"TQ==" (साफ़) M M M M

उस टेबल को दो बार पढ़िए, क्योंकि इसमें पूरा क़िस्सा है। डिफ़ॉल्ट base64decode() एक मिलनसार सीमा अधिकारी है: वह वर्णमाला से बाहर के चर छोड़ देता है, मिसिंग पैडिंग सह लेता है, और पूंछ वाले कंटेंट को अनदेखा करता है, इसलिए ईमेल-मंज़र की और क्लिपबोर्ड-मंज़र की स्ट्रिंग्स बस निकल जाती हैं। strict = TRUE मोड, जो लंबे सन्नाटे के बाद फ़रवरी 2026 में रिलीज़ 0.1-5 के साथ आया, वह फ़ोरेंसिक एग्ज़ामिनर है: वह पूरी स्ट्रिंग को वैलिडेट करता है, दोषी की ठीक-ठीक जगह बताता है, और सबक-किताब से बाहर सब चीज़ें ठुकरा देता है। b64 डिफ़ॉल्ट रूप से सख़्त है और आधी-आधी कभी कामयाब नहीं होता। और openssl असहज बीच में बैठा है: वह खुशी-खुशी व्हाइटस्पेस छोड़ देता है और मिसिंग पैडिंग पर सही तरह से एरर देता है, लेकिन जब उसे सच में ग़ैर-क़ानूनी चर या पूंछ वाला कचरा मिलता है, तो वह ख़ाली raw वेक्टर वापस कर देता है और बिल्कुल कुछ नहीं कहता। वह चुपचाप ख़ाली रिज़ल्ट पूरे इस लेख का सबसे ख़तरनाक व्यवहार है, तो चलिए उसे होते देखते हैं:

dirty <- "SGVsbG8s!IHdvcmxkIQ=="
openssl::base64_decode(dirty)
#> raw(0)   # ख़ाली। न एरर, न चेतावनी, न इशारा।

अगर आप openssl के ख़िलाफ़ कोड लिखते हैं, तो भरोसा करने से पहले जो मिला है उसकी लंबाई जाँच लीजिए। यह एक छोटी आदत है जो "मेरी डेटा कहाँ गई" जैसे पूरे ख़ानदान के रहस्यों से बचाती है।

सख़्त मोहरे के लिए, यहाँ base64enc को ठीक-ठीक काम करता हुआ देखिए, आपके अपने कंसोल में दिखने वाले बिल्कुल वैसे ही एरर मैसेज के साथ:

base64enc::base64decode("TWF u", strict = TRUE)
#> v=30000, pad=0, org='u'
#> Error: Invalid character (' ') at position 4 in base64 string (not allowed in strict mode)
base64enc::base64decode("TWF", strict = TRUE)
#> v=10000, pad=3, org=''
#> Error: Missing padding (1 characters) at the end of the base64 string (not allowed in strict mode)
base64enc::base64decode("TWF=xx", strict = TRUE)
#> v=20000, pad=0, org='xx'
#> Error: Trailing content 'xx' after padding at position 4 in base64 string (not allowed in strict mode)

एक अजीब बात का इंतज़ार रखिए: हर एक सख़्त कॉल, सफल हो या फ़ेल, कंसोल पर C-स्तर की एक स्टेटस लाइन फुफकारता है, कुछ ऐसा v=30000, pad=0, org='u' जैसा। यह कंपाइल्ड कोड से सीधे लिखा हुआ है, R वॉर्निंग नहीं, इसलिए suppressWarnings() इसे छू भी नहीं सकता। यह हानिरहित है, लेकिन अगर आपके टेस्ट कंसोल आउटपुट की तुलना करते हैं, तो अब आपको पता है कि एक अतिरिक्त पंक्ति क्यों है।

R की आदतें: NA, वेक्टर और चुपचाप जुड़ना

Base64 की अपनी अजीबियाँ हैं; R अपनी जोड़ देता है। पहली काट NA के रास्ते लगती है। जब आप NA_character_ किसी डिकोडर को देते हैं, तो R चुपचाप उसे स्ट्रिंग "NA" में बदल देता है, इससे पहले कि डिकोडर उसे देख भी पाए, और "NA" एक बिल्कुल वैध Base64 ग्रुप है। रिज़ल्ट न कोई एरर है और न ख़ाली वेक्टर। यह बाइट 0x34 है, अक्षर "4":

base64decode(NA_character_)
#> [1] 34
rawToChar(base64decode(NA_character_))
#> [1] "4"

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

values <- c("TWFu", NA_character_, "TQ==")
clean <- values[!is.na(values)]
out <- vapply(clean, function(x) rawToChar(base64decode(x)), character(1))
unname(out)
#> [1] "Man" "M"

दूसरी अजीबी वेक्टर इनपुट है, और डिकोडर बिल्कुल अलग-अलग मोड़ पर जाते हैं। base64decode() एक चर वेक्टर को एक ही स्ट्रिंग के कई टुकड़ों की तरह मानता है और उन्हें जोड़ देता है, इसलिए दो तत्व एक ही raw वेक्टर के रूप में वापस आते हैं। openssl::base64_decode() उस तक भी नहीं पहुँचता: वह अपने आर्ग्यूमेंट को सिकोड़ लेता है और फिर दो-तत्व वाले लॉजिकल टेस्ट में फँसता है, जो R के सबसे ईमानदार एरर मैसेज में से एक पैदा करता है। और b64::decode() एकमात्र है जो सच में वेक्टराइज़्ड है, हर इनपुट पर एक डिकोड किया हुआ ब्लॉब वापस करता है:

base64decode(c("TWFu", "TQ=="))
#> [1] 4d 61 6e 4d
openssl::base64_decode(c("TWFu", "TQ=="))
#> Error in if (is.na(text)) : the condition has length > 1
out <- b64::decode(c("TWFu", "TQ=="))
rawToChar(out[[1]])
#> [1] "Man"
rawToChar(out[[2]])
#> [1] "M"

याद रखने लायक बात: जान-बूझ कर लूप कीजिए या वेक्टराइज़ कीजिए, और कभी भी यह मानकर चलिए कि इनपुट का वेक्टर आपको आउटपुट का वेक्टर देगा।

URL-सुरक्षित वर्णमाला

स्टैंडर्ड Base64 अपनी वर्णमाला के अंतिम दो स्थान + और / पर खर्च करता है, और बिल्कुल वही चर हैं जिन्हें URL पसंद नहीं करते। प्लस बन जाता है %2B, स्लैश बन जाता है %2F, और पैडिंग बन जाती है %3D, इसलिए एक टोकन जो हर जगह पेस्ट होना चाहिए, पर्सेंट चिह्नों को पहनने लगता है। URL-सुरक्षित रूप, जिसकी परिभाषा RFC 4648 सेक्शन 5 में है, उन दो चरों की जगह - और _ रखता है और आमतौर पर पैडिंग भी गिरा देता है। R के पास उस दुनिया के लिए तीन दरवाज़े हैं।

दरवाज़ा नंबर एक b64 के इंजन हैं। इंजन बस एक सेट की गई वर्णमाला और पैडिंग नीति है, और पैकेज चारों इंजन साथ देता है जो आपको चाहिए:

library(b64)
std <- encode(as.raw(c(0xfb, 0xef, 0xbe)))
std
#> [1] "++++"
url <- encode(as.raw(c(0xfb, 0xef, 0xbe)), engine("url_safe"))
url
#> [1] "----"
decoded <- decode(url, engine("url_safe"))[[1]]
toString(decoded)
#> [1] "fb, ef, be"

इंजन हैं "standard" (डिफ़ॉल्ट), "standard_no_pad", "url_safe", और "url_safe_no_pad", और वही इंजन ऑब्जेक्ट दोनों दिशाओं में काम करता है, जिससे आपका कोड सिमेट्रिक रहता है। अपनी वर्णमाला के सवाल में ये सख़्त भी हैं: स्टैंडर्ड इंजन को "----" खिलाइए और वह जवाब देता है "Invalid byte 45, offset 0.", जो राहत की बात है।

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

base64url::base64_urlencode("hello world")
#> [1] "aGVsbG8gd29ybGQ"
base64url::base64_urldecode("aGVsbG8g!!!")
#> [1] "hello "   # बाक़ी चुपचाप गिरा दिया गया

दरवाज़ा नंबर तीन jose है, जो JWT काम के लिए base64url_encode() और base64url_decode() एक्सपोर्ट करता है, और raw वेक्टर वापस करता है ठीक वैसे जैसे आप उम्मीद करेंगे।

और जब आपको कभी-कभी का एक-मुश्त काम हो और आप base64enc के अंदर ही रहना चाहें, तो स्ट्रिंग सर्जरी और पैडिंग फिक्स क़ाफ़ी है:

url <- "----"
fixed <- gsub("_", "/", gsub("-", "+", url), fixed = TRUE)
padded <- switch(as.character(nchar(fixed) %% 4L),
  "0" = fixed,
  "2" = paste0(fixed, "=="),
  "3" = paste0(fixed, "="))
rawToChar(base64decode(padded))
#> [1] "\xfb\xef\xbe"

JWTs: झाँकना और भरोसा

ज़्यादातर लोग URL-सुरक्षित Base64 से JSON Web Token की वजह से मिलते हैं। JWT तीन base64url हिस्से हैं जो बिंदुओं से जुड़े होते हैं: एक हेडर जो बताता है कि यह कैसे साइन हुआ, एक क्लेमों का पेलोड, और एक सिग्नेचर जो पूरे को विश्वसनीय बनाता है। R में पहले दो हिस्सों को डिकोड करना पाँच पंक्तियों का काम है। strsplit() में fixed = TRUE पर नज़र रखिए: बिंदु एक रेगुलर एक्सप्रेशन वाइल्डकार्ड है, और उस फ़्लैग के बिना R खुशी-खुशी आपके टोकन को अकेले चरों में चिर देता है, जो बाज़ार में R कोड की सबसे आम Base64 ग़लती है।

jwt <- jose::jwt_encode_hmac(jose::jwt_claim(sub = "1234567890", iat = 1516239022, name = "John Doe"), "0123456789abcdef")
parts <- strsplit(jwt, ".", fixed = TRUE)[[1]]
header <- base64url::base64_urldecode(parts[1])
header
#> [1] "{\"typ\":\"JWT\",\"alg\":\"HS256\"}"
payload <- jsonlite::fromJSON(base64url::base64_urldecode(parts[2]))
payload$name
#> [1] "John Doe"

दो ईमानदार चेतावनियाँ। पहली, JWT डिकोड करना झाँकना है, भरोसा नहीं: तीसरा हिस्सा सिग्नेचर है, और वह तभी कोई काम का होता है जब इसे जारीकर्ता की कुंजी के ख़िलाफ़ जाँचा जाए। इसका पूरा ख़ानदान jose पैकेज संभालता है। उसकी 2.0 रिलीज़ (अप्रैल 2026) ED25519 सपोर्ट जोड़ती है और typ हेडर को वैकल्पिक बना देती है; पुराने ट्यूटोरियल जो 1.x के jwk_read()/jwk_write() हेल्पर (या उनके read_jwk()/write_jwk() एलियास) दिखाते हैं, वैध ही रहते हैं, क्योंकि 2.0 आज भी वही JWK पढ़ने-लिखने वाले हेल्पर साथ देती है:

library(jose)
claims <- jwt_decode_hmac(jwt, "0123456789abcdef")
claims$name
#> [1] "John Doe"
claims$sub
#> [1] "1234567890"
sp <- jwt_split(jwt)
sp$header
#> $alg
#> [1] "HS256"
#>
#> $typ
#> [1] "JWT"
sp$payload$name
#> [1] "John Doe"

jwt_decode_hmac() सिग्नेचर की पुष्टि करता है और साथ ही exp और nbf क्लेमों को लागू भी करता है, अगर टोकन एक्सपायर्ड हो तो एरर उठाता है। और दूसरी बात: base64url::base64_urldecode() और उसके साथी हेडर और पेलोड आराम से डिकोड कर लेते हैं, लेकिन सिग्नेचर वाला हिस्सा बायनेरी है, इसलिए उसे एक ऐसे फ़ंक्शन से डिकोड कीजिए जो raw वापस करे ("url_safe_no_pad" इंजन के साथ b64::decode() जैसा), स्ट्रिंग में नहीं।

कैरेक्टर सेट: वे बाइट्स क्या टेक्स्ट हैं?

इस लेख का हर एक डिकोडर जान-बूझ कर raw वेक्टर की सीमा पर रुकता है, क्योंकि "वह क्या टेक्स्ट था?" का जवाब इस बात पर निर्भर करता है कि बाइट्स किस कैरेक्टर सेट में पैक किए गए थे। आगे की अच्छी खबर: अगर भेजने वाले ने UTF-8 इस्तेमाल किया, जो आधुनिक वेब का ज़्यादातर हिस्सा है, तो आपकी ज़िंदगी छोटी और ख़ुशनुमा होगी। base64enc इसके लिए एक गेट भी साथ देता है:

packed <- base64encode(charToRaw("caf\u00e9"))
bytes <- base64decode(packed)
checkUTF8(bytes, quiet = TRUE)
#> [1] TRUE
rawToChar(bytes)
#> [1] "café"

checkUTF8() बिना किसी बाध्यता के पूछता है "क्या ये बाइट्स UTF-8 के रूप में पढ़े जा सकते हैं?" quiet = TRUE के साथ वह TRUE या FALSE वापस करता है; डिफ़ॉल्ट में तो वह और भी सीधा है और ग़लत बाइट्स पर एरर उठाता है, दोषी का नाम लेकर, जैसे INVALID byte 0xff at 0x0 (0, line 1): invalid start byte (FE/FF)। NUL बाइट्स वाली स्ट्रिंग्स के लिए भी वह FALSE रिपोर्ट करता है, क्योंकि वे वैध UTF-8 R स्ट्रिंग का हिस्सा हो ही नहीं सकते। इसे गेट की तरह इस्तेमाल कीजिए, और बाक़ी सब अपने-आप साथ आएगा।

यहीं समझ आता है कि गेट क्यों मायने रखता है। UTF-8 लोकल में, अगर बाइट्स वैध UTF-8 नहीं हैं, तो rawToChar() एरर नहीं फेंकता। वह आपको एक स्ट्रिंग सौंपता है जो R Encoding() == "unknown" से चिह्नित करता है, और लोकल और R बिल्ड के हिसाब से वही कॉल "invalid multibyte sequence" एरर के साथ मर भी सकती है, जो कम-से-कम ईमानदार है। दोनों ही तरह, अजनबी बाइट्स पर बिना बचाव डाला हुआ rawToChar() ही वह राह है जिससे mojibake का जन्म होता है:

broken <- as.raw(c(0xc3, 0x28))   # एक कटी हुई UTF-8 जोड़ी
checkUTF8(broken, quiet = TRUE)
#> [1] FALSE
rawToChar(broken)                  # कोई एरर नहीं। वही समस्या है।
#> [1] "\xc3("

और जब भेजने वाले ने बिल्कुल कुछ और इस्तेमाल किया हो, Latin-1 या Windows-1252 या Shift-JIS, तो रेसिपी यह है: raw में डिकोड कीजिए और फिर iconv() से बदलिए, जो नामी कैरेक्टर सेट्स को समझता है:

latin1_bytes <- as.raw(c(0x63, 0x61, 0x66, 0xe9))   # Latin-1 में "café"
iconv(rawToChar(latin1_bytes), from = "latin1", to = "UTF-8")
#> [1] "café"

इमोजी को एक ख़ास ज़िक्र का हक़ है, क्योंकि R की यहाँ अपनी कहानी है। आधुनिक R U+FFFF से ऊपर के कोड पॉइंट्स, जहाँ इमोजी रहते हैं, सच्चे UTF-8 के रूप में स्टोर करता है, इसलिए राउंड ट्रिप काम करता है और बाइट काउंट हर दूसरी भाषा की उम्मीद से मेल खाता है। पुराने R रिलीज़ वही चर स्यूरोगेट जोड़ी के रूप में स्टोर करती थीं, एक पद्धति जो अक्सर CESU-8 कहलाती है, इसलिए एक इमोजी सीमा पार करते समय छह बाइट्स की अमान्य UTF-8 बन जाता था। अगर आपको पुराना R कोड मिले जहाँ इमोजी वायर पर ख़राब पहुँचती हैं, तो यही पहला शकिया है: nchar(x, type = "bytes") जाँचिए और भेजने वाली भाषा के बनाए बाइट्स से तुलना कीजिए।

emoji <- "\U0001F600"
nchar(emoji, type = "bytes")
#> [1] 4
round_trip <- base64decode(base64encode(charToRaw(emoji)))
identical(emoji, rawToChar(round_trip))
#> [1] TRUE

अनुभव का नियम: UTF-8 मानिए, checkUTF8() से जाँचिए, और iconv() की ओर तभी बढ़िए जब आपको किसी दूसरे कैरेक्टर सेट की पक्की जानकारी हो। कभी अंदाज़ा न लगाइए।

फ़ाइलें: रैप्ड टेक्स्ट से असली बाइट्स तक

स्ट्रिंग आसान हैं; फ़ाइलें वही जगह है जहाँ Base64 अपनी कमाई करता है। उस मैनुअल पाइपलाइन से शुरुआत कीजिए जो किसी भी पैकेज के साथ चलती है: एन्कोडेड टेक्स्ट पढ़िए, डिकोड कीजिए, बाइट्स लिखिए।

cat("SGVsbG8sIHdvcmxkIQ==", file = "hello.b64")
bytes <- base64decode(paste(readLines("hello.b64"), collapse = ""))
writeBin(bytes, "hello.txt")
readLines("hello.txt")
#> [1] "Hello, world!"

फिर सुविधा की परत। base64enc आपके लिए पढ़-लिख सकता है: file आर्ग्यूमेंट उस फ़ाइल की ओर इशारा करता है जिसमें Base64 टेक्स्ट है, और output उस जगह की ओर जहाँ डिकोड किए गए बाइट्स उतरें। रिटर्न वैल्यू लिखे गए बाइट्स की संख्या है, एक बिल्कुल मुफ़्त, प्यारी सी सेनिटी चेक:

n <- base64decode(file = "hello.b64", output = "hello.txt")
n
#> [1] 13
readLines("hello.txt")
#> [1] "Hello, world!"

रैप्ड इनपुट, वही किस्म जो ईमेल या PEM कवच से बचकर निकला है, दयालु डिकोडरों के लिए कोई समस्या नहीं है: वे लाइन ब्रेक्स के ऊपर सीधे देखते हैं, चाहे वे कहीं भी पड़े हों, बशर्ते जो बच जाए वैध Base64 हो। MIME 76 चरों पर रैप करता है और पंक्तियों के बीच CRLF रखता है; PEM ब्लॉक्स 64 पर रैप करते हैं। सख़्त इंजन, जाहिर है, रैपिंग को सीधे ही ठुकरा देता है।

wrapped <- paste0("VGhlIHF1aWNrIGJ", "\r\n",
  "yb3duIGZveCBqdW1wcyBvdmVyIHRoZSBsYXp5IGRvZw==")
rawToChar(base64decode(wrapped))
#> [1] "The quick brown fox jumps over the lazy dog"
rawToChar(openssl::base64_decode(wrapped))
#> [1] "The quick brown fox jumps over the lazy dog"
b64::decode(wrapped)
#> Error: Invalid byte 13, offset 15.

b64 पैकेज की फ़ाइल जोड़ी के सबसे साफ़ नाम हैं, और क्योंकि यह Rust-तेज़ है, बड़ी फ़ाइल के लिए यही वह औज़ार है जिसके लिए हाथ बढ़ाना चाहिए। लेकिन एक तेज़ किनारा है: decode_file() फ़ाइल को बाइट-दर-बाइट पढ़ता है और क्षमा करने वाला नहीं है। एक ट्रेलिंग न्यूलाइन - वही किस्म जो writeLines() जोड़ता है लेकिन cat() कभी नहीं - Rust इंजन को पैनिक करवा देता है, जो कैच किया जा सकने वाले एरर के रूप में सतह पर आता है, User function panicked: decode_file_ जैसे। एन्कोडेड टेक्स्ट cat() या writeBin(charToRaw(enc), path) से लिखिए और किनारा मंद ही रहेगा।

writeBin(charToRaw("file payload bytes"), "payload.bin")
enc <- b64::encode_file("payload.bin")
cat(enc, file = "payload.b64")
bytes <- b64::decode_file("payload.b64")
rawToChar(bytes)
#> [1] "file payload bytes"

base64 पैकेज तीसरा रास्ता है: पूरा-पूरा फ़ाइल-ओरिएंटेड, एक मिलती-जुलती फ़ंक्शन जोड़ी के साथ:

base64::encode("payload.bin", "payload.b64")
base64::decode("payload.b64", "payload.out")
readLines("payload.out")
#> [1] "file payload bytes"

असल काम में आपको मिलने वाली एक और फ़ाइल शक्ल: एक data frame कॉलम जिसमें एन्कोडेड ब्लॉब भरे हों, API डम्प्स में बहुत आम। कुछ सौ पंक्तियों के लिए एक सादा वेक्टराइज़्ड कॉल क़ाफ़ी है:

df <- data.frame(content = c(b64::encode("alpha"), b64::encode("beta"),
  b64::encode("gamma")))
decoded <- b64::decode(df$content)
df$decoded <- vapply(decoded, function(x) rawToChar(x), character(1))
df$decoded
#> [1] "alpha" "beta"  "gamma"

APIs और वेब रिस्पॉन्स

JSON APIs बायनेरी को टेक्स्ट में घुसाना पसंद करते हैं, और Base64 उनका पसंदीदा सुटकेस है। R में पैटर्न हर बार वही है: ले आइए, पार्स कीजिए, डिकोड कीजिए, और तय कीजिए कि बाइट्स क्या हैं। आधुनिक HTTP क्लाइंट httr2 है, और JSON की तरफ jsonlite:

library(httr2)
library(jsonlite)
res <- req_perform(request("https://httpbin.org/get?attachment=TWFuIGlzIGhlcmU%3D&name=man.txt"))
data <- fromJSON(rawToChar(res$body))
bytes <- base64decode(data$args$attachment)
writeBin(bytes, data$args$name)
length(bytes)
#> [1] 11

राह की तीन बातें। रिक्वेस्ट का कन्स्ट्रक्टर request() है, और httr2 की पहली रिलीज़ से ही यह उसी नाम से चल रहा है। रिस्पॉन्स बॉडी raw वेक्टर के रूप में आती है, इसलिए JSON के रूप में पार्स करने से पहले rawToChar() कीजिए। और API कोई डायलैक्ट बोल सकता है: इसे ऐसे डिकोडर को खिलाने से पहले जाँच लीजिए कि उसका Base64 URL-सुरक्षित है या पैडिंग छील दिए जाने वाला, जो सबक-किताब वाला संस्करण उम्मीद करे। कुछ APIs तो डबल-एन्कोड तक करते हैं, Base64 का Base64, और आप पहचान जाएंगे जब एक डिकोड की जगह आगे और Base64 मिले, उम्मीद किए बाइट्स के बजाय।

Data URIs और स्व-पर्याप्त दस्तावेज़

data: URI स्कीम (RFC 2397) एक दस्तावेज़ को अपनी अपनी सामग्री साथ ले जाने देती है: MIME टाइप, पेलोड एन्कोडेड होने पर "base64" शब्द, और पेलोड स्वयं। आप इनसे स्क्रैप किए गए HTML में बार-बार मिलेंगे, और एक को डिकोड करना दो कदमों का स्ट्रिंग ऑपरेशन है जिसके बाद एक साधारण डिकोड होता है:

img_tag <- "<img src=\"data:image/png;base64,iVBORw0KGgoAAA\" />"
uri <- regmatches(img_tag, regexec("src=\"([^\"]*)\"", img_tag))[[1]][2]
uri
#> [1] "data:image/png;base64,iVBORw0KGgoAAA"
payload <- sub("^data:[^,]*,", "", uri)
bytes <- base64decode(payload)
length(bytes)
#> [1] 10

वही शक्ल CSS में दिखती है, PDF टिप्पणियों में, और स्व-पर्याप्त R Markdown रिपोर्ट्स में, जहाँ एक प्लॉट को <img> टैग में चपटा कर दिया जाता है ताकि HTML बिना किसी बग़ल वाली फ़ाइल के यात्रा कर सके। अगर आप ऐसे दस्तावेज़ रेंडर कर रहे हैं और एम्बेडेड इमेज बाहर निकालना चाहते हैं, तो पूरा उपाय यही है: data: स्ट्रिंग ढूँढिए, पहले कॉमा पर काटिए, डिकोड कीजिए।

डेटाबेस, ईमेल और कॉन्फ़िग

जब भी किसी को टेक्स्ट कॉलम के अंदर बायनेरी चाहिए, तब डेटाबेस में Base64 दिखता है, और डिकोड की तरफ है स्ट्रिंग्स की कॉलम को वापस बाइट्स में लाना। यहाँ DBI और RSQLite के रास्ते SQLite पर राउंड ट्रिप है: एन्कोडेड वैल्यू स्टोर कीजिए, क्वेरी करके लौटाइए, डिकोड कीजिए, और आपके पास आपके बाइट्स हैं:

library(DBI)
library(RSQLite)
db <- dbConnect(SQLite(), ":memory:")
dbExecute(db, "CREATE TABLE files (name TEXT, payload TEXT)")
stored <- base64encode(charToRaw("stored in a database"))
dbExecute(db, paste0("INSERT INTO files VALUES ('note.txt', '", stored, "')"))
row <- dbGetQuery(db, "SELECT * FROM files")
rawToChar(base64decode(row$payload))
#> [1] "stored in a database"

SQLite बायनेरी को नैटिव रूप में BLOB के रूप में भी स्टोर कर सकता है, जिस स्थिति में Base64 की ज़रूरत ही नहीं होती और कॉलम R में raw वेक्टर के रूप में लौटता है, जैसे class(dbGetQuery(db, "SELECT payload FROM blobs")$payload[[1]]) == "raw"। TEXT में Base64 वाला रूप पोर्टेबिलिटी के लिए मौजूद है: आप इसे एक टेक्स्ट एडिटर से देख सकते हैं, और हर दूसरी भाषा इसे बिना बायनेरी ड्राइवर्स के पढ़ सकती है।

ईमेल वही जगह है जहाँ से रैप्ड Base64 आता है। MIME भाग 76 चरों पर रैप होते हैं और पंक्तियों के बीच CRLF रखते हैं, और आपने जो भी मेल सिस्टम पढ़ा है, उसने एटैचमेंट बिल्कुल ऐसे ही उठाए हैं। R के पास फर्स्ट-क्लास मेल क्लाइंट नहीं है, लेकिन जब आपको .eml फ़ाइल मिलती है, तो एटैचमेंट का base64 हिस्सा बस रैप्ड टेक्स्ट है: दयालु डिकोडर डिकोड करते हुए उसे अन-रैप भी कर देंगे। mime पैकेज आपको पहचानने में मदद करता है कि आपके हाथ में क्या है:

mime::guess_type("photo.jpg")
#> [1] "image/jpeg"
part <- "SGVsbG8s\r\nCnRoaXMgaXMgYW4g\r\nZW1haWwgYXR0YWNobWVudA=="
rawToChar(base64decode(part))
#> [1] "Hello,\nthis is an email attachment"

कॉन्फ़िग फ़ाइलें इस सफ़र को पूरा करती हैं। जब कोई सर्टिफ़िकेट या ब्लॉब YAML या JSON कॉन्फ़िग में, या किसी एनवायरनमेंट वेरिएबल में Base64-एन्कोडेड रूप में स्टोर किया जाता है, तो R उसे एक साधारण स्ट्रिंग के रूप में पढ़ता है और आप ज़रूरत पर डिकोड करते हैं:

config_line <- "api_cert: TFRTU0VDUkVU"
cert_b64 <- sub("^api_cert: ", "", config_line)
raws <- base64decode(cert_b64)
rawToChar(raws)
#> [1] "LTSSECRET"

बड़े पेलोड्स

R स्ट्रिंग्स की एक सख़्त छत है, 2^31 - 1 बाइट्स, और इतनी बड़ी Base64 स्ट्रिंग भी इससे टकरा सकती है, क्योंकि एन्कोडेड रूप मूल की तुलना में करीब एक-तिहाई बड़ा होता है। base64enc पैकेज अपनी 2022 रिलीज़ से ही इसका इंतज़ाम करता है: base64encode() को एक लाइन चौड़ाई दें और वह एक बहुत बड़ी स्ट्रिंग के बजाय पंक्तियों का वेक्टर वापस कर देगा, और डिकोड की तरफ file = आर्ग्यूमेंट फ़ाइल को पंक्तियों के रूप में पढ़कर डिकोड करता है, बिना आपको एक विशाल स्ट्रिंग को वेरिएबल में दबोचने पर मज़बूर किया।

कुछ सौ मेगाबाइट की फ़ाइलों के लिए, प्राक्टिकल पैटर्न है बराबर चंक में पढ़ना। Base64 ग्रुप्स आत्मनिर्भर हैं, इसलिए चार चरों के गुणज लंबाई वाला कोई भी चंक अकेले डिकोड हो जाता है; आप को सिर्फ़ एक छोटा बफ़र चाहिए टूटे-फूटे सिरे को साथ ले जाने के लिए:

chunk <- 65536L
con <- file("huge.b64", "rb")
on.exit(close(con))
leftover <- ""
out <- raw(0)
while (TRUE) {
  piece <- readChar(con, chunk, useBytes = TRUE)
  if (length(piece) == 0) break
  piece <- gsub("[\r\n]", "", piece)
  ready <- paste0(leftover, piece)
  take <- floor(nchar(ready) / 4) * 4
  if (take > 0) {
    out <- c(out, base64decode(substr(ready, 1, take)))
    leftover <- substr(ready, take + 1, nchar(ready))
  } else {
    leftover <- ready
  }
}
if (nchar(leftover) > 0) out <- c(out, base64decode(leftover))
length(out)

इस इलाके में b64 पैकेज स्पीड चैंपियन है: उसका Rust इंजन 50-मेगाबाइट फ़ाइल को सेकंड के एक हिस्से में डिकोड कर देता है, और उसका वेक्टराइज़्ड decode() एक कॉल में एन्कोडेड वैल्यूज़ की पूरी कॉलम संभाल लेता है, जो पंक्ति-दर-पंक्ति लूप से बिल्कुल भिन्न बात है। अगर आपके पास कई स्ट्रिंग्स हैं, तो खुद एक तेज़ system.time() तुलना चलाइए; पंक्ति-दर-पंक्ति लूप और एक वेक्टराइज़्ड कॉल के बीच का फ़ासला आमतौर पर इतना बड़ा होता है कि यह मायने रखता है।

कमांड लाइन

हर काम को पूरी R सेशन की ज़रूरत नहीं होती। क्लासिक Unix औज़ार Base64 को नैटिव रूप में बोलते हैं, और R उन्हें काम सौंप सकता है या उनके पास से काम ले सकता है। Linux पर base64 -d डिकोड करता है (macOS और अन्य BSD सिस्टम -D इस्तेमाल करते हैं):

echo "SGVsbG8sIHdvcmxkIQ==" | base64 -d
#> Hello, world!

और एक पंक्ति की Rscript वही काम कर देती है, आपके स्क्रिप्ट्स में इस्तेमाल होने वाले वही पैकेज के साथ:

Rscript -e 'library(base64enc); writeLines(rawToChar(base64decode("TWFu")))'
#> Man

तेज़ जाँचों और पाइप के लिए शेल इस्तेमाल कीजिए; जब रिज़ल्ट को data frame, फ़ाइल, या रिपोर्ट में बसना हो, तब R कीजिए। एक सावधानी: कमांड-लाइन आर्ग्यूमेंट्स की एक साइज़ लिमिट (ARG_MAX) होती है, इसलिए कई मेगाबाइट की स्ट्रिंग्स को टर्मिनल में पेस्ट न कीजिए। बजाय इसके इन्हें फ़ाइल के रास्ते पाइप कीजिए।

जानने लायक गड्ढे

यहाँ वह छोटी लिस्ट है जिसमें बताया गया है कि यह R डेवलपर्स को कैसे काटता है, और ये सारे एकोसिस्टम के अपने हैं, Base64 की सामान्य बातें नहीं:

  • openssl चुपचाप फ़ेल होता है। जब वर्णमाला से बाहर का चर या पूंछ वाला कचरा मिलता है, तो base64_decode() न एरर और न वॉर्निंग, बस ख़ाली raw वेक्टर वापस कर देता है। भरोसा करने से पहले रिज़ल्ट की length() हमेशा जाँचिए।
  • डिकोडर के लिए NA कोई मिसिंग वैल्यू नहीं है। NA_character_ स्ट्रिंग "NA" में बदल जाता है, जो बाइट 0x34 में डिकोड होता है। डिकोड करने से पहले NA फ़िल्टर कीजिए।
  • वेक्टर आपकी उम्मीद के अनुसार नहीं चलते। base64decode() अपने इनपुट को एक ही raw वेक्टर में जोड़ देता है; openssl::base64_decode() बहु-तत्व इनपुट पर the condition has length > 1 के साथ मर जाता है; सच में वेक्टराइज़्ड केवल b64::decode() है।
  • rawToChar एक चुपचाप ख़राब करने वाला है। UTF-8 लोकल में अमान्य UTF-8 बाइट्स एरर नहीं उठाते; वे "unknown" चिह्नित स्ट्रिंग बन जाती हैं। पहले checkUTF8() से गेट कीजिए।
  • JWT में बिंदु एक रेगुलर एक्सप्रेशन वाइल्डकार्ड है। fixed = TRUE के बिना strsplit(jwt, ".") हर चर पर काट देता है। यह R कोड की सबसे आम Base64 ग़लती है।
  • b64 फ़ाइलें क्षमा नहीं करतीं। एन्कोडेड फ़ाइल में ट्रेलिंग न्यूलाइन b64::decode_file() को पैनिक करवा देता है। writeLines() के बजाय cat() से लिखिए।
  • दयालु, भरोसे के लिए क़ाफ़ी नहीं। base64decode() का डिफ़ॉल्ट मोड कहीं भी ग़लत चर छोड़ देता है, इसलिए एक ख़राब स्ट्रिंग बिना एरर के ऐसे कचरे में डिकोड हो सकती है जो सही-सही दिखे। भरोसे की सीमाओं पर strict = TRUE इस्तेमाल कीजिए।
  • b64 के एरर मैसेज Rust बोलते हैं। जब आप उसे वह टाइप दें जो वह नहीं चाहता, तो Both cases of Either errored जैसे वाक्यों की उम्मीद रखिए। मैसेज जान-बूझ कर बेकाम होता है; यह Rust टाइप सिस्टम का कंधे उछोलना है।

बेहतरीन प्रथाएँ

  • रोज़मर्रा के काम के लिए base64enc::base64decode() को डिफ़ॉल्ट रखिए, और strict = TRUE हर जगह चालू कीजिए जहाँ इनपुट एक भरोसे की सीमा पार करे: अविश्वसनीय APIs, यूज़र की अपलोड, कुछ भी साइन की हुई चीज़।
  • जब आपको स्पीड, सच्चा वेक्टराइज़ेशन, या URL-सुरक्षित और बिना-पैडिंग इंजन चाहिए, तब b64 की ओर बढ़िए, और यह स्वीकारिए कि वह डिज़ाइन के हिसाब से सख़्त है।
  • अगर openssl आपके प्रोजेक्ट में पहले से है, तो इस्तेमाल कीजिए, लेकिन हर रिज़ल्ट को शकनगीन समझिए, जब तक उसकी लंबाई न जाँच लीजिए।
  • कैरेक्टर सेट जान-बूझ कर तय कीजिए: UTF-8 मानिए, checkUTF8() से जाँचिए, और iconv() तभी इस्तेमाल कीजिए जब भेजने वाले ने कुछ और बताया हो।
  • JWTs के लिए strsplit() और fixed = TRUE के साथ झाँकिए, लेकिन तभी भरोसा कीजिए जब jose सिग्नेचर की पुष्टि कर ले।
  • अपने टेस्ट्स में TWFu रखिए: यह आपकी लिखी हर डिकोड पथ के लिए तीन बाइट्स का स्मोक टेस्ट है।
  • याद रखिए कि Base64 क्या नहीं है: यह एन्क्रिप्शन नहीं है, और यह कॉम्प्रेसन नहीं है। यह पैकिंग टेप है, और इस लेख वाला कोई भी व्यक्ति इसका हर काम उल्टा कर सकता है। जो चाहें उतना डिकोड कीजिए, भरोसा चुन-चुन कर कीजिए।

R में Base64: एक छोटा सा इतिहास

फ़ॉर्मैट पुराना है। 1987 में इसे Privacy-Enhanced Mail प्रोटोकॉल के लिए मानकीकृत किया गया (RFC 989), 1993 में MIME ने अपनाया (RFC 1521, फिर 1996 में अंतिम RFC 2045), 2003 में RFC 3548 ने इसे साफ़-सुथरा किया, और 2006 में RFC 4648 ने उसे आधुनिक शक्ल दी, जिसमें URL-सुरक्षित वर्णमाला शामिल है। R की कहानी बहुत छोटी है और तेज़ी से आगे बढ़ती है। base64enc पैकेज, Simon Urbanek द्वारा, पहली बार सितंबर 2012 में CRAN पर उतरा और तब से कामकाज की रीढ़ बना हुआ है, 2015 में checkUTF8() और 2022 में लॉन्ग वेक्टर सपोर्ट पाता हुआ। अक्टूबर 2024 में पुराना base64 पैकेज खुल कर एक कंपैटिबिलिटी रैपर के रूप में दोबारा जारी हुआ, और उसका अपना वर्णन अब नई ऐप्लिकेशन को base64enc, openssl या jsonlite की ओर ले जाता है। फिर 2024 की शुरुआत में b64 आया (वर्तमान रिलीज़ 0.1.7, जुलाई 2025), extendr से बना Rust इंजन, जिसने सच्चा वेक्टराइज़ेशन और वर्णमालाओं का एक पूरा समूह लाई। फ़रवरी 2026 में base64enc ने अपनी लंबे समय से मांगी गई सख़्त मोड रिलीज़ की, और अप्रैल 2026 में jose पैकेज ने jwt_* फ़ंक्शनों के चारों ओर खुद को नई-से डिज़ाइन किया। वही जो बाक़ी भाषाओं ने एक लाइब्रेरी में शिप किया, उसके लिए दस साल, लेकिन नतीजा एक टूलबॉक्स है जहाँ हर डिकोडर का स्पष्ट काम है और स्पष्ट शख़्सियत।

मज़ेदार तथ्य

क्योंकि एक पूरा-पूरा गाइड एक मुस्कान के साथ ख़त्म होना चाहिए:

  • base64decode(NA_character_) अक्षर "4" वापस करता है, क्योंकि NA_character_ स्ट्रिंग "NA" के रूप में डिकोडर तक पहुँचता है, और "NA" एक वैध Base64 ग्रुप है। भाषा का सबसे R-ख़ास वन-बाइट सरप्राइज़।
  • openssl::base64_decode() को एक ही ग़ैर-क़ानूनी चर वाली स्ट्रिंग दो और वह बिल्कुल चुप्पी में raw(0) वापस कर देता है। एकोसिस्टम की सबसे ख़तरनाक चुप्पी।
  • base64decode() की हर एक सख़्त कॉल C-स्तर की v=30000, pad=0, org='u' जैसी स्टेटस लाइन फुफकारती है। यह वॉर्निंग नहीं है। यह C कोड की गला साफ़ करना है।
  • b64 ऐसी वर्णमालाएँ भी डिकोड कर सकता है जो आपने कभी नहीं देखी: BinHex, IMAP modified UTF-7, और bcrypt और crypt की कस्टम वर्णमालाएँ। वही इंजन R में 1980 के दशक की Macintosh एटैचमेंट और आधुनिक पासवर्ड हैश दोनों पढ़ सकता है।
  • R स्ट्रिंग्स 2^31 - 1 बाइट्स पर रुक जाती हैं, इसलिए base64enc ने लंबे इनपुट के लिए पंक्तियों का वेक्टर वापस करना सीखा। फ़ॉर्मैट भाषा की दीवार से टकराया, और पैकेज ने एक सीढ़ी पाल ली।
  • शब्द "base64" YmFzZTY0 में एन्कोड होता है। वह फ़ॉर्मैट जो खुद को समझा सकता है, वह एक ऐसा आईना है जो मोर्स बोलता है।
  • एक अकेला NUL बाइट आज भी चार चरों की कीमत का है: "AA=="। Base64 में कुछ न होना हमेशा कुछ होता है।
  • आपके R बिल्ड का एक उपनाम है। R 4.5.0 को "How About a Twenty-Six" कहा जाता है, क्योंकि R वर्ज़न्स Peanuts कॉमिक्स और फ़िल्मों के नाम पर रखे जाते हैं, और वह स्ट्रिप जिसका नाम लिया जाता है, वह उस रिलीज़ से दशकों पुरानी होती है। जिस वर्ज़न से आप डिकोड कर रहे हैं, उसके पास भी हँसी की समझ है।

सारांश

अपना डिकोडर उसी संगत के हिसाब से चुनिए जिसके बीच आप रहते हैं: रोज़मर्रा के काम के लिए base64enc, किनारों पर strict = TRUE के साथ; openssl अगर वह पहले से आपके प्रोजेक्ट में है, बशर्ते आप अपने रिज़ल्ट्स की जाँच कर रहे हों; b64 जब आपको स्पीड, वेक्टर, और URL-सुरक्षित इंजन चाहिए; और छोटे विशेषज्ञ base64 और base64url फ़ाइल के कामों और URL-सुरक्षित स्ट्रिंग्स के लिए। बाइट्स को टेक्स्ट कहने से पहले checkUTF8() से उनकी रखवाली कीजिए, कैरेक्टर सेट कुछ और पक्का हो तो iconv() इस्तेमाल कीजिए, और याद रखिए कि बीच वाला raw वेक्टर एक फीचर है: यह आपको बाइट्स का मतलब तय करने के लिए मज़बूर करता है, किसी लाइब्रेरी को अंदाज़े लगाने के बजाय। सब कुछ डिकोड कीजिए, उस पर ही भरोसा कीजिए जिसकी पुष्टि हो। और जब आपको दूसरी दिशा में जाना हो, अपनी बाइट्स को एक स्ट्रिंग में पैक करके सफ़र पर भेजना, किसी स्ट्रिंग को खोलने के बजाय, तो बहन साइट का संगत लेख R में Base64 एन्कोडिंग को विस्तार से कवर करता है।

अंतिम अपडेट: 2026-09-08

संबंधित लेख: R में Base64 एन्कोडिंग: एक सम्पूर्ण गाइड