मैं मैन्युअल रूप से एन्कोडिंग निर्दिष्ट किए बिना C # में स्ट्रिंग्स का लगातार बाइट प्रतिनिधित्व कैसे प्राप्त करूं?


2189

मैं मैन्युअल रूप से एक विशिष्ट एन्कोडिंग निर्दिष्ट किए बिना .NET (सी #) में ए stringको कैसे परिवर्तित कर सकता हूं byte[]?

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

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


23
हर स्ट्रिंग को बाइट्स के एक सरणी के रूप में संग्रहीत किया जाता है? मैं बस उन बाइट्स क्यों नहीं कर सकते?
एगेल कुरियन

135
एन्कोडिंग वह है जो पात्रों को बाइट्स में मैप करता है। उदाहरण के लिए, ASCII में, अक्षर 'A' नंबर 65 पर मैप करता है। एक अलग एन्कोडिंग में, यह समान नहीं हो सकता है। .NET फ्रेमवर्क में लिए गए स्ट्रिंग्स का उच्च-स्तरीय दृष्टिकोण इसे काफी हद तक अप्रासंगिक बनाता है, हालाँकि (इस मामले को छोड़कर)।
लुकास जोन्स

20
शैतान के वकील की भूमिका निभाने के लिए: यदि आप इन-मेमोरी स्ट्रिंग के बाइट्स प्राप्त करना चाहते हैं (जैसे कि .NET उनका उपयोग करता है) और उन्हें किसी भी तरह से हेरफेर करें (यानी CRC32), और कभी भी इसे मूल स्ट्रिंग में वापस डिकोड नहीं करना चाहता था ... सीधे आगे नहीं है कि आप एन्कोडिंग के बारे में क्यों ध्यान रखेंगे या आप किस तरह का उपयोग करना चाहते हैं।
ग्रेग

78
आश्चर्यचकित किसी ने अभी तक यह लिंक नहीं दिया है: joelonsoftware.com/articles/Unicode.html
Bevan

28
एक चार बाइट नहीं है और एक बाइट चार नहीं है। एक फॉन्ट एक फॉन्ट टेबल में एक कुंजी और एक लेक्सिकल परंपरा दोनों है। एक तार वर्णों का एक क्रम है। (एक शब्द, पैराग्राफ, वाक्य, और शीर्षक भी अपनी स्वयं की शब्द परंपराएं हैं जो अपनी स्वयं की परिभाषाओं को सही ठहराते हैं - लेकिन मैं पचाता हूं)। पूर्णांक की तरह, फ्लोटिंग पॉइंट नंबर, और बाकी सब, वर्ण बाइट्स में एन्कोडेड होते हैं। एक समय था जब एन्कोडिंग एक से एक सरल था: ASCII। हालांकि, सभी मानव सहजीवन को समायोजित करने के लिए, एक बाइट के 256 क्रमचय अपर्याप्त थे और चुनिंदा रूप से अधिक बाइट्स का उपयोग करने के लिए एन्कोडिंग को तैयार किया गया था।
जॉर्ज

जवाबों:


1855

यदि आप बाइट्स की व्याख्या करने की आवश्यकता नहीं है, तो यहां उत्तरों के विपरीत, आपको एन्कोडिंग के बारे में चिंता करने की आवश्यकता नहीं है!

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

उन लक्ष्यों के लिए, मुझे ईमानदारी से समझ में नहीं आता है कि लोग आपको क्यों बता रहे हैं कि आपको एन्कोडिंग की आवश्यकता है। आपको निश्चित रूप से इसके लिए एन्कोडिंग के बारे में चिंता करने की आवश्यकता नहीं है।

इसके बजाय बस करें:

static byte[] GetBytes(string str)
{
    byte[] bytes = new byte[str.Length * sizeof(char)];
    System.Buffer.BlockCopy(str.ToCharArray(), 0, bytes, 0, bytes.Length);
    return bytes;
}

// Do NOT use on arbitrary bytes; only use on GetBytes's output on the SAME system
static string GetString(byte[] bytes)
{
    char[] chars = new char[bytes.Length / sizeof(char)];
    System.Buffer.BlockCopy(bytes, 0, chars, 0, bytes.Length);
    return new string(chars);
}

जब तक आपके कार्यक्रम (या अन्य कार्यक्रम) किसी भी तरह बाइट्स की व्याख्या करने की कोशिश नहीं करते हैं , जो कि आपने स्पष्ट रूप से उल्लेख नहीं किया है कि आप ऐसा करने का इरादा रखते हैं, तो इस दृष्टिकोण में कुछ भी गलत नहीं है! एन्कोडिंग के बारे में चिंता करना आपके जीवन को बिना किसी वास्तविक कारण के अधिक जटिल बनाता है।

इस दृष्टिकोण के लिए अतिरिक्त लाभ:

इससे कोई फर्क नहीं पड़ता कि स्ट्रिंग में अमान्य वर्ण हैं, क्योंकि आप अभी भी डेटा प्राप्त कर सकते हैं और वैसे भी मूल स्ट्रिंग को फिर से संगठित कर सकते हैं!

इसे एनकोड और डीकोड किया जाएगा, क्योंकि आप सिर्फ बाइट्स देख रहे हैं ।

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


247
क्या बदसूरत है के बारे में यह एक है कि GetStringऔर GetBytesकाम करने के लिए एक ही endianness के साथ एक सिस्टम पर निष्पादित करने की आवश्यकता। तो आप बाइट्स प्राप्त करने के लिए इसका उपयोग नहीं कर सकते हैं जिसे आप कहीं और स्ट्रिंग में बदलना चाहते हैं। इसलिए मेरे पास ऐसी परिस्थितियों के साथ आने का कठिन समय है जहां मैं इसका उपयोग करना चाहता हूं।
कोडइन्चोस

72
@CodeInChaos: जैसा मैंने कहा, इसका पूरा मतलब यह है कि अगर आप एक ही तरह के सिस्टम पर एक ही तरह के फंक्शन के साथ इसका इस्तेमाल करना चाहते हैं। यदि नहीं, तो आपको इसका उपयोग नहीं करना चाहिए।
user541686

193
-1 मैं गारंटी देता हूं कि कोई व्यक्ति (जो बाइट्स बनाम कैरेक्टर नहीं समझता है) अपनी स्ट्रिंग को बाइट सरणी में बदलना चाहता है, वे इसे गूगल करेंगे और इस उत्तर को पढ़ेंगे, और वे गलत काम करेंगे, क्योंकि लगभग सभी में मामलों, एन्कोडिंग आईएस प्रासंगिक है।
आर्टब्रिस्टल

401
@ सारब्रिस्टल: यदि उन्हें उत्तर (या अन्य उत्तर ...) पढ़ने के लिए परेशान नहीं किया जा सकता है, तो मुझे खेद है, तो मेरे लिए उनके साथ संवाद करने का इससे बेहतर तरीका नहीं है। मैं आमतौर पर ओपी को जवाब देने के बजाय यह अनुमान लगाने की कोशिश करता हूं कि दूसरे मेरे जवाब के साथ क्या कर सकते हैं - ओपी को यह जानने का अधिकार है, और सिर्फ इसलिए कि कोई व्यक्ति चाकू का दुरुपयोग कर सकता है इसका मतलब यह नहीं है कि हमें दुनिया में सभी चाकू छिपाने की जरूरत है हमारे लिए। हालांकि अगर आप असहमत हैं तो वह भी ठीक है।
user541686

185
यह उत्तर इतने सारे स्तरों पर गलत है, लेकिन सबसे महत्वपूर्ण यह है कि घोषणा के कारण "आपको एन्कोडिंग के बारे में चिंता करने की आवश्यकता नहीं है।" 2 विधियाँ, GetBytes और GetString उतने ही शानदार हैं, जितने कि वे केवल एन्कोडिंग का पुन: कार्यान्वयन हैं। Unicode.GetBytes () और Encoding.Unicode.GetString () पहले से ही हैं। बयान "जब तक आपके कार्यक्रम (या अन्य कार्यक्रम) बाइट्स की व्याख्या करने की कोशिश नहीं करते हैं" भी मौलिक रूप से त्रुटिपूर्ण है क्योंकि उनका अर्थ है कि बाइट्स को यूनिकोड के रूप में व्याख्या किया जाना चाहिए।
डेविड

1108

यह आपके स्ट्रिंग ( ASCII , UTF-8 , ...) के एन्कोडिंग पर निर्भर करता है ।

उदाहरण के लिए:

byte[] b1 = System.Text.Encoding.UTF8.GetBytes (myString);
byte[] b2 = System.Text.Encoding.ASCII.GetBytes (myString);

एक छोटा सा नमूना क्यों एन्कोडिंग मायने रखता है:

string pi = "\u03a0";
byte[] ascii = System.Text.Encoding.ASCII.GetBytes (pi);
byte[] utf8 = System.Text.Encoding.UTF8.GetBytes (pi);

Console.WriteLine (ascii.Length); //Will print 1
Console.WriteLine (utf8.Length); //Will print 2
Console.WriteLine (System.Text.Encoding.ASCII.GetString (ascii)); //Will print '?'

ASCII केवल विशेष वर्णों से निपटने के लिए सुसज्जित नहीं है।

आंतरिक रूप से, .NET फ्रेमवर्क स्ट्रिंग्स का प्रतिनिधित्व करने के लिए UTF-16 का उपयोग करता है , इसलिए यदि आप केवल सटीक बाइट्स प्राप्त करना चाहते हैं जो .NET उपयोग करता है, तो उपयोग करें System.Text.Encoding.Unicode.GetBytes (...)

अधिक जानकारी के लिए .NET फ्रेमवर्क (MSDN) में कैरेक्टर एनकोडिंग देखें ।


14
लेकिन, एन्कोडिंग को क्यों ध्यान में रखा जाना चाहिए? मैं केवल यह देखने के लिए बिना बाइट्स क्यों प्राप्त कर सकता हूं कि एन्कोडिंग का उपयोग किया जा रहा है? यहां तक ​​कि अगर यह आवश्यक था, तो स्ट्रिंग ऑब्जेक्ट को खुद नहीं पता होना चाहिए कि एन्कोडिंग का क्या उपयोग किया जा रहा है और बस मेमोरी में क्या डंप है?
एगनेल कुरियन

57
एक .NET स्ट्रिंग्स को हमेशा यूनिकोड के रूप में एन्कोड किया जाता है। इसलिए System.Text.Encoding.Unicode.GetBytes () का उपयोग करें; बाइट्स के सेट को पाने के लिए। .NET वर्णों का प्रतिनिधित्व करने के लिए उपयोग करेगा। हालाँकि आप ऐसा क्यों चाहेंगे? मैं यूटीएफ -8 की सिफारिश करता हूं, खासकर जब ज्यादातर पात्र पश्चिमी लैटिन सेट में होते हैं।
एंथनीवजोन

8
इसके अलावा: स्ट्रिंग में आंतरिक रूप से उपयोग किए जाने वाले सटीक बाइट्स को कोई फर्क नहीं पड़ता अगर सिस्टम जो उन्हें पुनर्प्राप्त करता है वह उस एन्कोडिंग को संभालता नहीं है या इसे गलत एन्कोडिंग के रूप में संभालता है। अगर यह सब .Net में है, तो बाइट्स की एक सरणी में क्यों परिवर्तित करें। अन्यथा, आपके एन्कोडिंग के साथ स्पष्ट होना बेहतर है
जोएल कोएहॉर्न

11
@Joel, System.Text.Encoding.Default के साथ सावधान रहें क्योंकि यह चलने वाली प्रत्येक मशीन पर अलग हो सकती है। यही कारण है कि यह हमेशा एक एन्कोडिंग निर्दिष्ट करने के लिए अनुशंसित है, जैसे कि यूटीएफ -8
ऐश २

25
जब तक आप (या कोई और) वास्तव में डेटा की व्याख्या करने का इरादा नहीं रखते तब तक एन्कोडिंग की आवश्यकता नहीं है , बजाय इसे एक सामान्य "बाइट्स के ब्लॉक" के रूप में व्यवहार करने के लिए। संपीड़न, एन्क्रिप्शन, आदि जैसी चीजों के लिए, एन्कोडिंग के बारे में चिंता करना व्यर्थ है। एन्कोडिंग के बारे में चिंता किए बिना ऐसा करने के तरीके के लिए मेरा जवाब देखें । (मैं आपको यह
बताने के

285

स्वीकृत उत्तर बहुत जटिल है। इसके लिए शामिल .NET क्लासेस का उपयोग करें:

const string data = "A string with international characters: Norwegian: ÆØÅæøå, Chinese: 喂 谢谢";
var bytes = System.Text.Encoding.UTF8.GetBytes(data);
var decoded = System.Text.Encoding.UTF8.GetString(bytes);

यदि आपको ...


14
यदि रिकॉर्ड किए गए उत्तर को बदल दिया जाता है, तो रिकॉर्ड उद्देश्यों के लिए, यह वर्तमान समय और तारीख में मेहरदाद का जवाब है। उम्मीद है कि ओपी इस पर दोबारा गौर करेगा और बेहतर समाधान स्वीकार करेगा।
थॉमस ईडिंग

7
सिद्धांत रूप में अच्छा है, लेकिन एन्कोडिंग System.Text.Encoding.Unicodeमेहरदाद के उत्तर के बराबर होना चाहिए ।
जोडरेल

5
मूल उत्तर के बाद से प्रश्न को एक umptillion बार संपादित किया गया है, इसलिए, शायद मेरा जवाब थोड़ा अलग है। मैंने कभी भी मेहरदाद के जवाब के बराबर एक एक्सस देने का इरादा नहीं किया, लेकिन इसे करने का एक समझदार तरीका दिया। लेकिन, आप सही हो सकते हैं। हालांकि, मूल प्रश्न में वाक्यांश "क्या बाइट्स स्ट्रिंग संग्रहीत किया गया है" मिलता है, बहुत ही अनिश्चित है। संग्रहीत, कहाँ? याद में? डिस्क पर? यदि स्मृति में, System.Text.Encoding.Unicode.GetBytesसंभवतः अधिक सटीक होगा।
एरिक ए। ब्रैंडस्टैडमेन

7
@AMissico, आपका सुझाव छोटी गाड़ी है, जब तक कि आप सुनिश्चित नहीं हैं कि आपका स्ट्रिंग आपके सिस्टम डिफ़ॉल्ट एन्कोडिंग (स्ट्रिंग आपके सिस्टम डिफ़ॉल्ट विरासत चार्ट में केवल ASCII वर्ण वाले) के साथ संगत है। लेकिन कहीं भी ओपी कहता है कि।
Frédéric

5
@AMissico यह कार्यक्रम को अलग- अलग प्रणालियों पर अलग- अलग परिणाम देने का कारण बन सकता है । यह कभी अच्छी बात नहीं है। यहां तक ​​कि अगर यह हैश या कुछ बनाने के लिए है (मुझे लगता है कि ओपी का अर्थ है 'एन्क्रिप्ट' के साथ), वही स्ट्रिंग अभी भी हमेशा उसी हैश को देना चाहिए।
Nyerguds

114
BinaryFormatter bf = new BinaryFormatter();
byte[] bytes;
MemoryStream ms = new MemoryStream();

string orig = "喂 Hello 谢谢 Thank You";
bf.Serialize(ms, orig);
ms.Seek(0, 0);
bytes = ms.ToArray();

MessageBox.Show("Original bytes Length: " + bytes.Length.ToString());

MessageBox.Show("Original string Length: " + orig.Length.ToString());

for (int i = 0; i < bytes.Length; ++i) bytes[i] ^= 168; // pseudo encrypt
for (int i = 0; i < bytes.Length; ++i) bytes[i] ^= 168; // pseudo decrypt

BinaryFormatter bfx = new BinaryFormatter();
MemoryStream msx = new MemoryStream();            
msx.Write(bytes, 0, bytes.Length);
msx.Seek(0, 0);
string sx = (string)bfx.Deserialize(msx);

MessageBox.Show("Still intact :" + sx);

MessageBox.Show("Deserialize string Length(still intact): " 
    + sx.Length.ToString());

BinaryFormatter bfy = new BinaryFormatter();
MemoryStream msy = new MemoryStream();
bfy.Serialize(msy, sx);
msy.Seek(0, 0);
byte[] bytesy = msy.ToArray();

MessageBox.Show("Deserialize bytes Length(still intact): " 
   + bytesy.Length.ToString());

2
आप उन सभी कार्यों के लिए एक ही बाइनरीफ़ॉर्मेट उदाहरण का उपयोग कर सकते हैं
जोएल कोएहॉर्न

3
बहुत ही रोचक। जाहिरा तौर पर यह किसी भी उच्च सरोगेट यूनिकोड चरित्र को छोड़ देगा। [

95

आपको एन्कोडिंग को ध्यान में रखना होगा, क्योंकि 1 चरित्र को 1 या अधिक बाइट्स (लगभग 6 तक) द्वारा दर्शाया जा सकता है , और अलग-अलग एन्कोडिंग इन बाइट्स को अलग तरह से व्यवहार करेंगे।

इस पर जोएल की एक पोस्टिंग है:

एब्सोल्यूट मिनिमम हर सॉफ्टवेयर डेवलपर बिल्कुल, यूनिकोड और कैरेक्टर सेट्स (नो एक्सक्यूज़) के बारे में सकारात्मक रूप से जानना चाहिए!


6
"1 चरित्र को 1 या अधिक बाइट्स द्वारा दर्शाया जा सकता है" मैं सहमत हूं। मैं सिर्फ उन बाइट्स की परवाह किए बिना चाहता हूं कि स्ट्रिंग में एन्कोडिंग क्या है। स्मृति में एक स्ट्रिंग को संग्रहीत करने का एकमात्र तरीका बाइट्स में है। यहां तक ​​कि पात्रों को 1 या अधिक बाइट्स के रूप में संग्रहीत किया जाता है। मैं केवल अपने हाथों को उन बाइट्स पर प्राप्त करना चाहता हूं।
एगेल कुरियन

16
जब तक आप (या कोई और) वास्तव में डेटा की व्याख्या करने का इरादा नहीं रखते तब तक एन्कोडिंग की आवश्यकता नहीं है , बजाय इसे एक सामान्य "बाइट्स के ब्लॉक" के रूप में व्यवहार करने के लिए। संपीड़न, एन्क्रिप्शन, आदि जैसी चीजों के लिए, एन्कोडिंग के बारे में चिंता करना व्यर्थ है। एन्कोडिंग के बारे में चिंता किए बिना ऐसा करने के तरीके के लिए मेरा जवाब देखें ।
user541686

9
@ मेहरदाद - पूरी तरह से, लेकिन मूल प्रश्न, जैसा कि मैंने शुरू में उत्तर दिया था, यह नहीं बताया कि ओपी उन बाइट्स के साथ क्या होने वाला था, क्योंकि वे उन्हें परिवर्तित कर देते थे, और भविष्य के खोजकर्ताओं के बारे में जानकारी जो प्रासंगिक है - यह जोएल के उत्तर को काफी अच्छी तरह से कवर किया गया है - और जैसा कि आप अपने जवाब के भीतर बताते हैं: बशर्ते आप .NET दुनिया के भीतर रहें, और अपने तरीकों को / से बदलने के लिए उपयोग करें, आप खुश हैं। जैसे ही आप उसके बाहर कदम रखेंगे, एन्कोडिंग मायने रखेगा।
ज़ाफ़ - बेन डुगुएड

एक कोड बिंदु को 4 बाइट तक दर्शाया जा सकता है । (एक UTF-32 कोड इकाई, एक UTF-16 सरोगेट जोड़ी, या UTF-8 की 4 बाइट्स।) उन मानों के लिए जो UTF-8 को 4 बाइट्स से अधिक की आवश्यकता होगी, वे यूनिकोड की 0x0..0x10FFFF श्रेणी के बाहर हैं। ;-)
DevSolar

89

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

सामान्य आवश्यकता

प्रत्येक स्ट्रिंग में एक वर्ण सेट और एन्कोडिंग है। जब आप System.Stringऑब्जेक्ट को किसी सरणी में परिवर्तित करते हैं तब System.Byteभी आपके पास एक वर्ण सेट और एन्कोडिंग होती है। अधिकांश उपयोगों के लिए, आपको पता होगा कि आपको कौन सा वर्ण सेट और एन्कोडिंग चाहिए और .NET को "रूपांतरण के साथ कॉपी करना" सरल बनाता है। बस उपयुक्त Encodingवर्ग चुनें।

// using System.Text;
Encoding.UTF8.GetBytes(".NET String to byte array")

रूपांतरण को उन मामलों को संभालने की आवश्यकता हो सकती है जहां लक्ष्य वर्ण सेट या एन्कोडिंग स्रोत में मौजूद किसी वर्ण का समर्थन नहीं करता है। आपके पास कुछ विकल्प हैं: अपवाद, प्रतिस्थापन या लंघन। डिफ़ॉल्ट नीति को '?' स्थानापन्न करना है।

// using System.Text;
var text = Encoding.ASCII.GetString(Encoding.ASCII.GetBytes("You win €100")); 
                                                      // -> "You win ?100"

स्पष्ट रूप से, रूपांतरण आवश्यक रूप से दोषरहित नहीं हैं!

नोट: System.Stringस्रोत वर्ण सेट के लिए यूनिकोड है।

केवल भ्रमित करने वाली बात यह है कि .NET उस वर्ण सेट के एक विशेष एन्कोडिंग के नाम के लिए निर्धारित वर्ण के नाम का उपयोग करता है। Encoding.Unicodeबुलाया जाना चाहिए Encoding.UTF16

यह सबसे usages के लिए है। यदि आपकी जरूरत है, तो यहां पढ़ना बंद करें। मज़ेदार जोएल स्पोलस्की लेख देखें यदि आपको समझ नहीं आता है कि एन्कोडिंग क्या है।

विशिष्ट आवश्यकता है

अब, सवाल लेखक पूछता है, "हर स्ट्रिंग को बाइट्स की एक सरणी के रूप में संग्रहीत किया जाता है, सही? मैं बस उन बाइट्स को क्यों नहीं कर सकता?"

वह कोई रूपांतरण नहीं चाहता है।

से सी # कल्पना :

सी # में चरित्र और स्ट्रिंग प्रसंस्करण यूनिकोड एन्कोडिंग का उपयोग करता है। Char प्रकार एक UTF-16 कोड इकाई का प्रतिनिधित्व करता है, और स्ट्रिंग प्रकार UTF-16 कोड इकाइयों के अनुक्रम का प्रतिनिधित्व करता है।

इसलिए, हम जानते हैं कि यदि हम अशक्त रूपांतरण (यानी UTF-16 से UTF-16 के लिए) पूछेंगे, तो हमें वांछित परिणाम मिलेगा:

Encoding.Unicode.GetBytes(".NET String to byte array")

लेकिन एनकोडिंग के उल्लेख से बचने के लिए, हमें इसे दूसरे तरीके से करना चाहिए। यदि कोई मध्यवर्ती डेटा प्रकार स्वीकार्य है, तो इसके लिए एक वैचारिक शॉर्टकट है:

".NET String to byte array".ToCharArray()

हमें वांछित डेटाटाइप नहीं मिलता है, लेकिन मेहरदाद का जवाब दिखाता है कि ब्लॉकचॉपी का उपयोग करके इस चार सरणी को बाइट सरणी में कैसे परिवर्तित किया जाए । हालाँकि, यह दो बार स्ट्रिंग को कॉपी करता है! और, यह स्पष्ट रूप से एन्कोडिंग-विशिष्ट कोड का उपयोग करता है: डेटाटाइप System.Char

वास्तविक बाइट्स को प्राप्त करने का एकमात्र तरीका स्ट्रिंग को एक पॉइंटर का उपयोग करने के लिए संग्रहीत किया जाता है। fixedबयान मूल्यों का पता लेने के लिए अनुमति देता है। सी # कल्पना से:

[के लिए] टाइप स्ट्रिंग की एक अभिव्यक्ति, ... इनिशलाइज़र स्ट्रिंग में पहले वर्ण के पते की गणना करता है।

ऐसा करने के लिए, कंपाइलर स्ट्रिंग ऑब्जेक्ट के अन्य हिस्सों के साथ कोड स्किप को लिखता है RuntimeHelpers.OffsetToStringData। तो, कच्चे बाइट्स प्राप्त करने के लिए, बस स्ट्रिंग को एक पॉइंटर बनाएं और आवश्यक बाइट्स की संख्या की प्रतिलिपि बनाएँ।

// using System.Runtime.InteropServices
unsafe byte[] GetRawBytes(String s)
{
    if (s == null) return null;
    var codeunitCount = s.Length;
    /* We know that String is a sequence of UTF-16 codeunits 
       and such codeunits are 2 bytes */
    var byteCount = codeunitCount * 2; 
    var bytes = new byte[byteCount];
    fixed(void* pRaw = s)
    {
        Marshal.Copy((IntPtr)pRaw, bytes, 0, byteCount);
    }
    return bytes;
}

जैसा कि @CodesInChaos ने बताया, परिणाम मशीन की समाप्ति पर निर्भर करता है। लेकिन प्रश्न लेखक का इससे कोई सरोकार नहीं है।


3
@ जान यह सही है लेकिन स्ट्रिंग की लंबाई पहले से ही कोड-यूनिट (कोडपॉइंट नहीं) की संख्या देती है।
टॉम ब्लोगेट

1
यह बात बताने के लिए धन्यवाद! MSDN से: " Lengthसंपत्ति [की String] Charइस उदाहरण में वस्तुओं की संख्या लौटाती है , यूनिकोड वर्णों की संख्या नहीं।" इसलिए आपका उदाहरण कोड लिखित रूप में सही है।
Jan Hettich

1
@supercat "चार प्रकार एक UTF-16 कोड इकाई का प्रतिनिधित्व करता है, और स्ट्रिंग प्रकार UTF-16 कोड इकाइयों के एक अनुक्रम का प्रतिनिधित्व करता है।" -_ C # 5 विशिष्टता._ हालांकि, हाँ, कुछ भी नहीं है जो एक अमान्य यूनिक स्ट्रिंग को रोकता है:new String(new []{'\uD800', '\u0030'})
टॉम ब्लोडेट

1
@TomBlodget: दिलचस्प बात यह है कि अगर कोई एक उदाहरण लेता है Globalization.SortKey, अर्क निकालता है KeyData, और परिणामस्वरूप बाइट्स को एक String[दो बाइट्स प्रति कैरेक्टर, MSB प्रथम ] में पैक करता है , String.CompareOrdinalतो इसके परिणामस्वरूप कॉलिंग कॉलिंग SortKey.Compareइंस्टेंस पर कॉल करने से SortKeyया तो तेज हो जाएगी या यहां तक ​​कि memcmpउन उदाहरणों पर कॉल करना। यह देखते हुए, मुझे आश्चर्य है कि KeyDataए के Byte[]बजाय रिटर्न क्यों String?
सुपरकाट

1
काश, सही जवाब, लेकिन साल बहुत देर हो चुकी है, स्वीकार किए जाते हैं के रूप में कई वोट कभी नहीं होगा। टीएल के कारण; डीआर लोग स्वीकृत उत्तर चट्टानों के बारे में सोचेंगे। copyenpastit और इसे वोट करें।
मार्टिन कैपोडिसी

46

आपके प्रश्न का पहला भाग (बाइट्स कैसे प्राप्त करें) पहले से ही दूसरों द्वारा उत्तर दिया गया था: System.Text.Encodingनाम स्थान में देखें।

मैं आपके अनुवर्ती प्रश्न को संबोधित करूंगा: आपको एन्कोडिंग चुनने की आवश्यकता क्यों है? आप उसे स्ट्रिंग क्लास से ही क्यों नहीं प्राप्त कर सकते?

इसका उत्तर दो भागों में है।

सबसे पहले, स्ट्रिंग क्लास द्वारा आंतरिक रूप से उपयोग किए जाने वाले बाइट्स कोई मायने नहीं रखते हैं , और जब भी आप मानते हैं कि आप संभवत: बग को पेश कर रहे हैं।

यदि आपका कार्यक्रम पूरी तरह से .Net दुनिया के भीतर है, तो आपको स्ट्रिंग्स के लिए बाइट एरेज़ प्राप्त करने के बारे में चिंता करने की ज़रूरत नहीं है, भले ही आप एक नेटवर्क पर डेटा भेज रहे हों। इसके बजाय, डेटा को प्रसारित करने के बारे में चिंता करने के लिए .Net सीरियललाइज़ेशन का उपयोग करें। आप किसी भी वास्तविक बाइट्स के बारे में चिंता न करें: सीरियलाइज़ेशन फॉर्मैटर आपके लिए करता है।

दूसरी ओर, क्या होगा यदि आप इन बाइट्स को कहीं भेज रहे हैं जो आप गारंटी नहीं दे सकते हैं कि एक .Net धारावाहिक धारा से डेटा में खींच जाएगा? इस मामले में आपको निश्चित रूप से एन्कोडिंग के बारे में चिंता करने की आवश्यकता है, क्योंकि जाहिर है कि यह बाहरी प्रणाली परवाह करती है। तो फिर से, स्ट्रिंग द्वारा उपयोग किए जाने वाले आंतरिक बाइट्स कोई फर्क नहीं पड़ता: आपको एन्कोडिंग लेने की आवश्यकता है ताकि आप प्राप्त एन्कोडिंग पर इस एन्कोडिंग के बारे में स्पष्ट हो सकें, भले ही यह आंतरिक रूप से उसी एन्कोडिंग द्वारा उपयोग किया गया हो।

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

जो मुझे दूसरे भाग के लिए लाता है ... उठा Unicodeएन्कोडिंग है नेट अंतर्निहित बाइट का उपयोग करने के लिए कह। आपको इस एन्कोडिंग को चुनने की आवश्यकता है, क्योंकि जब कुछ नए-फंसे हुए यूनिकोड-प्लस बाहर निकलते हैं। नेट रनटाइम को आपके प्रोग्राम को तोड़ने के बिना इस नए, बेहतर एन्कोडिंग मॉडल का उपयोग करने के लिए स्वतंत्र होने की आवश्यकता है। लेकिन, फिलहाल (और भविष्य के लिए), यूनिकोड एनकोडिंग को चुनने से आपको वही मिलता है जो आप चाहते हैं।

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


9
.NET में ऐसे क्षेत्र हैं जहाँ आपको स्ट्रिंग्स के लिए बाइट सरणियाँ प्राप्त करनी होती हैं। .NET क्रिप्टोग्राफी कक्षाओं में से कई में ComputeHash () जैसे तरीके हैं जो बाइट सरणी या स्ट्रीम को स्वीकार करते हैं। आपके पास पहले स्ट्रिंग को बाइट सरणी में बदलने के लिए (एन्कोडिंग चुनने) के अलावा कोई विकल्प नहीं है और फिर इसे वैकल्पिक रूप से एक धारा में लपेट दें। हालाँकि जब तक आप एक एन्कोडिंग (यानी UTF8) चुनते हैं, तब तक इसके साथ एक छड़ी होती है, इससे कोई समस्या नहीं होती है।
ऐश २

44

बस यह प्रदर्शित करने के लिए कि मेहरदाद का ध्वनि उत्तर काम करता है, उसका दृष्टिकोण अप्रभावित सरोगेट पात्रों को भी बनाए रख सकता है (जिनमें से कई ने मेरे उत्तर के खिलाफ स्तर लगाया था, लेकिन जिनमें से हर कोई समान रूप से दोषी है ; उदाहरण के लिए System.Text.Encoding.UTF8.GetBytes, System.Text.Encoding.Unicode.GetBytesउन एन्कोडिंग विधियों में उच्च सरोगेट बना रह सकता है; d800उदाहरण के लिए वर्ण , और वे केवल उच्च मूल्य वाले उच्च वर्णों को प्रतिस्थापित करते हैं fffd):

using System;

class Program
{     
    static void Main(string[] args)
    {
        string t = "爱虫";            
        string s = "Test\ud800Test"; 

        byte[] dumpToBytes = GetBytes(s);
        string getItBack = GetString(dumpToBytes);

        foreach (char item in getItBack)
        {
            Console.WriteLine("{0} {1}", item, ((ushort)item).ToString("x"));
        }    
    }

    static byte[] GetBytes(string str)
    {
        byte[] bytes = new byte[str.Length * sizeof(char)];
        System.Buffer.BlockCopy(str.ToCharArray(), 0, bytes, 0, bytes.Length);
        return bytes;
    }

    static string GetString(byte[] bytes)
    {
        char[] chars = new char[bytes.Length / sizeof(char)];
        System.Buffer.BlockCopy(bytes, 0, chars, 0, bytes.Length);
        return new string(chars);
    }        
}

आउटपुट:

T 54
e 65
s 73
t 74
? d800
T 54
e 65
s 73
t 74

System.Text.Encoding.UTF8.GetBytes या System.Text.Encoding.Unicode.GetBytes के साथ कोशिश करें कि वे महज फफूंद के साथ उच्च सरोगेट वर्णों को बदल देंगे।

हर बार इस सवाल में एक आंदोलन है, मैं अभी भी एक धारावाहिक (यह Microsoft से या 3 पार्टी घटक से हो) के बारे में सोच रहा हूं जो स्ट्रिंग को जारी रख सकता है यहां तक ​​कि इसमें अनपेक्षित सरोगेट वर्ण भी हैं; मैं यह हर अब और फिर गूगल: क्रमांकन unpaired सरोगेट चरित्र .NET । इससे मुझे कोई नींद नहीं आती है, लेकिन यह तब परेशान करने वाला होता है जब हर कोई मेरे जवाब पर टिप्पणी कर रहा होता है कि यह त्रुटिपूर्ण है, फिर भी अनपेक्षित सरोगेट पात्रों की बात आती है तो उनके जवाब भी उतने ही त्रुटिपूर्ण हैं।

अरे, माइक्रोसॉफ्ट सिर्फ इस्तेमाल किया जाना चाहिए था System.Buffer.BlockCopyअपने में BinaryFormatter

谢谢!


3
वैध कोड बिंदु बनाने के लिए सरोगेट्स को जोड़े में नहीं दिखना चाहिए? अगर ऐसा है, तो मैं समझ सकता हूं कि डेटा क्यों मंगवाया जाएगा।
dtanders

1
@dtanders हां, मेरे विचार भी यही हैं, उन्हें जोड़े में दिखना है, बिना सरोगेट के किरदार सिर्फ इसलिए होते हैं, अगर आप जानबूझकर उन्हें स्ट्रिंग पर रख देते हैं और उन्हें अनपेयर कर देते हैं। मुझे नहीं पता कि अन्य देवता क्यों परेशान रहते हैं कि हमें इसके बजाय एन्कोडिंग-जागरूक दृष्टिकोण का उपयोग करना चाहिए, क्योंकि उन्होंने क्रमबद्धता दृष्टिकोण ( मेरा उत्तर , जो 3 साल से अधिक के लिए एक स्वीकृत उत्तर था) को अनपेक्षित नहीं रखा है सरोगेट चरित्र बरकरार है। लेकिन वे यह जांचना भूल गए कि उनके एन्कोडिंग-जागरूक समाधान अप्रभावित सरोगेट चरित्र भी नहीं रखते हैं, विडंबना en
माइकल बुएन

यदि System.Buffer.BlockCopyआंतरिक रूप से उपयोग करने वाला एक क्रमांकन पुस्तकालय है , तो सभी एन्कोडिंग-एडवोकेसी लोगों की दलीलें मूट हो जाएंगी
माइकल बुएन

2
@MichaelBuen मुझे ऐसा लगता है कि मुख्य मुद्दा यह है कि आप बड़े मोटे अक्षरों में कह रहे हैं कि कुछ मायने नहीं रखता, बल्कि यह कहता है कि यह उनके मामले में मायने नहीं रखता। नतीजतन, आप उन लोगों को प्रोत्साहित कर रहे हैं जो आपके उत्तर को बुनियादी प्रोग्रामिंग गलतियों को बनाने के लिए देखते हैं जो भविष्य में दूसरों को हताशा का कारण बना देगा। एक स्ट्रिंग में अमान्य सरोगेट अमान्य हैं। यह एक वर्ण सरणी नहीं है, इसलिए यह समझ में आता है कि एक स्ट्रिंग को दूसरे प्रारूप में परिवर्तित करने के परिणामस्वरूप FFFDउस चरित्र पर एक त्रुटि होगी । यदि आप मैन्युअल स्ट्रिंग हेरफेर करना चाहते हैं, तो अनुशंसित के रूप में एक चार [] का उपयोग करें।
त्रिकोणीय

2
@ डांडर्स: ए System.Stringएक अपरिवर्तनीय अनुक्रम है Char; .NET ने हमेशा Stringकिसी भी वस्तु से निर्माण करने की अनुमति दी है Char[]और अपनी सामग्री को Char[]समान मानों के साथ निर्यात किया है , भले ही मूल Char[]में अप्रमाणित सरोगेट्स हों।
सुपरकैट

41

यह कोशिश करो, बहुत कम कोड:

System.Text.Encoding.UTF8.GetBytes("TEST String");

फिर यह कोशिश करो System.Text.Encoding.UTF8.GetBytes("Árvíztűrő tükörfúrógép);, और रोओ! यह काम करेगा, लेकिन System.Text.Encoding.UTF8.GetBytes("Árvíztűrő tükörfúrógép").Length != System.Text.Encoding.UTF8.GetBytes("Arvizturo tukorfurogep").Lengthजबकि"Árvíztűrő tükörfúrógép".Length == "Arvizturo tukorfurogep".Length
mg30rg

9
@ mg30rg: आपको क्यों लगता है कि आपका उदाहरण अजीब है? निश्चित रूप से एक चर-चौड़ाई एन्कोडिंग में सभी वर्णों की बाइट लंबाई समान नहीं होती है। इसके साथ गलत क्या है?
व्लाद

@Vlad यहां एक अधिक मान्य टिप्पणी है, हालांकि यह है कि एन्कोडेड यूनिकोड प्रतीकों के रूप में (इसलिए, बाइट्स के रूप में), वर्ण जो अपने स्वयं के डायक्रिटिक्स को शामिल करते हैं , वे चरित्र में जोड़े गए न्यूट्रीशियन से अलग होने वाले संशोधक प्रतीकों से अलग परिणाम देंगे । लेकिन iirc में एक विशेष बाइट प्रतिनिधित्व प्राप्त करने की अनुमति देने के लिए .net में विशेष रूप से उन बंदों को विभाजित करने के तरीके हैं।
Nyerguds

25

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

उदाहरण के लिए, स्ट्रिंग खराब है, उदाहरण के लिए, SQL सर्वर से आता है जहां इसे बाइट सरणी भंडारण से बनाया गया था, उदाहरण के लिए, पासवर्ड हैश। यदि हम इसमें से कुछ भी गिराते हैं, तो यह एक अमान्य हैश संग्रहीत करेगा, और यदि हम इसे XML में संग्रहीत करना चाहते हैं, तो हम इसे अक्षुण्ण रखना चाहते हैं (क्योंकि XML लेखक किसी भी अनपेक्षित सरोगेट पर एक अपवाद को छोड़ देता है)।

तो मैं ऐसे मामलों में बाइट सरणियों के बेस 64 एन्कोडिंग का उपयोग करता हूं , लेकिन हे, इंटरनेट पर सी # में इसका केवल एक ही समाधान है, और इसमें बग है और केवल एक ही रास्ता है, इसलिए मैंने बग को ठीक कर दिया है और वापस लिखा है प्रक्रिया। यहाँ आप भविष्य के गोगलर्स हैं:

public static byte[] StringToBytes(string str)
{
    byte[] data = new byte[str.Length * 2];
    for (int i = 0; i < str.Length; ++i)
    {
        char ch = str[i];
        data[i * 2] = (byte)(ch & 0xFF);
        data[i * 2 + 1] = (byte)((ch & 0xFF00) >> 8);
    }

    return data;
}

public static string StringFromBytes(byte[] arr)
{
    char[] ch = new char[arr.Length / 2];
    for (int i = 0; i < ch.Length; ++i)
    {
        ch[i] = (char)((int)arr[i * 2] + (((int)arr[i * 2 + 1]) << 8));
    }
    return new String(ch);
}

बाइट सरणी को आधार 64 में बदलने के लिए अपनी कस्टम विधि का उपयोग करने के बजाय, आपको बस इतना करना था कि अंतर्निहित कनवर्टर का उपयोग करें: Convert.ToBase64String (गिरफ्तार);
मकोतोसन

@ माकोतोसन धन्यवाद, लेकिन मैंने Convert.ToBase64String(arr); बेस 64 रूपांतरणों के लिए उपयोग किया byte[] (data) <-> string (serialized data to store in XML file)। लेकिन प्रारंभिक प्राप्त करने के लिए byte[] (data)एक साथ कुछ करने की जरूरत है मैं Stringकि निहित बाइनरी डेटा (यह तरीका MSSQL मेरे लिए लौट आए है)। उपर्युक्त कार्य इसके लिए हैं String (binary data) <-> byte[] (easy accessible binary data)
गमन

23

कृपया यह भी बताएं कि एन्कोडिंग को क्यों ध्यान में रखा जाना चाहिए। क्या मैं आसानी से उस बाइट को प्राप्त नहीं कर सकता जो स्ट्रिंग में संग्रहीत किया गया है? एन्कोडिंग पर यह निर्भरता क्यों? !!!

क्योंकि "स्ट्रिंग के बाइट्स" जैसी कोई चीज नहीं है।

एक स्ट्रिंग (या अधिक उदारता से, एक पाठ) वर्णों से बना है: अक्षर, अंक और अन्य प्रतीक। बस इतना ही। कंप्यूटर, हालांकि, वर्णों के बारे में कुछ भी नहीं जानते हैं; वे केवल बाइट्स संभाल सकते हैं। इसलिए, यदि आप कंप्यूटर का उपयोग करके पाठ को संग्रहीत या संचारित करना चाहते हैं, तो आपको वर्णों को बाइट में बदलने की आवश्यकता है। आप उसे कैसे करते हैं? यहाँ जहाँ दृश्य के लिए एनकोडिंग हैं।

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

तो, संक्षेप में, "एन्कोडिंग का उपयोग किए बिना एक स्ट्रिंग के बाइट्स प्राप्त करने की कोशिश करना" उतना ही असंभव है जितना कि "किसी भी भाषा का उपयोग किए बिना एक पाठ लिखना"।

वैसे, मैं आपको (और किसी को भी, उस मामले के लिए) ज्ञान के इस छोटे से टुकड़े को पढ़ने के लिए दृढ़ता से सलाह देता हूं: निरपेक्ष न्यूनतम हर सॉफ्टवेयर डेवलपर बिल्कुल, यूनिकोड और चरित्र सेट (कोई बहाना नहीं!) के बारे में सकारात्मक रूप से जानना चाहिए।


2
मुझे स्पष्ट करने की अनुमति दें: भौतिक बाइट्स के लिए "हैलो वर्ल्ड" का अनुवाद करने के लिए एन्कोडिंग का उपयोग किया गया है। चूंकि स्ट्रिंग मेरे कंप्यूटर पर संग्रहीत है, मुझे यकीन है कि इसे बाइट्स में संग्रहीत किया जाना चाहिए। मैं केवल उन बाइट्स को डिस्क पर या किसी अन्य कारण से सहेजना चाहता हूं। मैं इन बाइट्स की व्याख्या नहीं करना चाहता। चूंकि मैं इन बाइट्स की व्याख्या नहीं करना चाहता, इसलिए इस बिंदु पर एन्कोडिंग की आवश्यकता उतनी ही गलत है जितना कि प्रिंटफ को कॉल करने के लिए फोन लाइन की आवश्यकता होती है।
एगेल कुरियन

3
लेकिन फिर से, पाठ-से-शारीरिक-बाइट्स-अनुवाद की कोई अवधारणा नहीं है जब तक कि यो एक एन्कोडिंग का उपयोग न करें। यकीन है, संकलक मेमोरी में किसी भी तरह से तारों को संग्रहीत करता है - लेकिन यह सिर्फ एक आंतरिक एन्कोडिंग का उपयोग कर रहा है, जिसे आप (या कंपाइलर डेवलपर को छोड़कर) कोई नहीं जानता है। इसलिए, आप जो भी करते हैं, आपको एक स्ट्रिंग से भौतिक बाइट्स प्राप्त करने के लिए एन्कोडिंग की आवश्यकता होती है।
कोनामिमन

@ एगेल कुरियन: यह बिल्कुल सच है, कि एक स्ट्रिंग में बाइट्स का एक गुच्छा होता है जो इसकी सामग्री (UTF-16 afair) को संग्रहीत करता है। लेकिन आपको इसे एक्सेस करने से रोकने का एक अच्छा कारण है: तार अपरिवर्तनीय हैं और यदि आप आंतरिक बाइट [] सरणी प्राप्त कर सकते हैं, तो आप इसे संशोधित भी कर सकते हैं। यह अपरिवर्तनीयता को तोड़ता है, जो महत्वपूर्ण है क्योंकि कई तार एक ही डेटा साझा कर सकते हैं। स्ट्रिंग प्राप्त करने के लिए UTF-16 एन्कोडिंग का उपयोग करना संभवत: डेटा को कॉपी करना होगा।
ollb

2
@Gnafoo, बाइट्स की एक प्रति होगी।
एगेल कुरियन

22

stringकिसी byteसरणी में बदलने के लिए C # :

public static byte[] StrToByteArray(string str)
{
   System.Text.UTF8Encoding  encoding=new System.Text.UTF8Encoding();
   return encoding.GetBytes(str);
}

17
byte[] strToByteArray(string str)
{
    System.Text.ASCIIEncoding enc = new System.Text.ASCIIEncoding();
    return enc.GetBytes(str);
}

लेकिन, एन्कोडिंग को क्यों ध्यान में रखा जाना चाहिए? मैं केवल यह देखने के लिए बिना बाइट्स क्यों प्राप्त कर सकता हूं कि एन्कोडिंग का उपयोग किया जा रहा है? यहां तक ​​कि अगर यह आवश्यक था, तो स्ट्रिंग ऑब्जेक्ट को खुद नहीं पता होना चाहिए कि एन्कोडिंग का क्या उपयोग किया जा रहा है और बस मेमोरी में क्या डंप है?
एगेल कुरियन

5
यह हमेशा काम नहीं करता है। कुछ विशेष वर्ण ऐसी विधि का उपयोग करने में खो सकते हैं जो मैंने कठिन रास्ता पाया है।
जेबी किंग

17

आप स्ट्रिंग और बाइट सरणी के बीच रूपांतरण के लिए निम्न कोड का उपयोग कर सकते हैं।

string s = "Hello World";

// String to Byte[]

byte[] byte1 = System.Text.Encoding.Default.GetBytes(s);

// OR

byte[] byte2 = System.Text.ASCIIEncoding.Default.GetBytes(s);

// Byte[] to string

string str = System.Text.Encoding.UTF8.GetString(byte1);

VUPthis एक ने मेरी समस्या को हल किया (बाइट] [ff = ASCIIEncoding.ASCII.GetBytes (barcodetxt.Text);)
r.hamd

16

Span<T>सी # 7.2 के साथ जारी होने के आगमन के साथ, एक प्रबंधित बाइट सरणी में स्ट्रिंग की अंतर्निहित मेमोरी प्रतिनिधित्व को पकड़ने के लिए विहित तकनीक:

byte[] bytes = "rubbish_\u9999_string".AsSpan().AsBytes().ToArray();

इसे वापस बदलना एक गैर-स्टार्टर होना चाहिए क्योंकि इसका मतलब है कि आप वास्तव में किसी भी तरह डेटा की व्याख्या कर रहे हैं, लेकिन पूर्णता के लिए:

string s;
unsafe
{
    fixed (char* f = &bytes.AsSpan().NonPortableCast<byte, char>().DangerousGetPinnableReference())
    {
        s = new string(f);
    }
}

नामों NonPortableCastऔर DangerousGetPinnableReferenceइस तर्क को आगे बढ़ाना चाहिए कि शायद आपको ऐसा नहीं करना चाहिए।

ध्यान दें कि साथ काम Span<T>करने के लिए System.Memory NuGet पैकेज की आवश्यकता होती है ।

इसके बावजूद, वास्तविक मूल प्रश्न और अनुवर्ती टिप्पणियों का अर्थ है कि अंतर्निहित स्मृति को "व्याख्या" नहीं किया जा रहा है (जो मुझे लगता है कि संशोधित नहीं है या इसे लिखने की आवश्यकता से परे पढ़ा जाता है), यह दर्शाता है कि Streamकक्षा के कुछ कार्यान्वयन। डेटा के बारे में तर्क के बजाय उपयोग किया जाना चाहिए।


13

मुझे यकीन नहीं है, लेकिन मुझे लगता है कि स्ट्रिंग अपनी जानकारी को चर की एक सरणी के रूप में संग्रहीत करती है, जो बाइट्स के साथ अक्षम है। विशेष रूप से, एक चार की परिभाषा "एक यूनिकोड चरित्र का प्रतिनिधित्व करता है" है।

इस उदाहरण का नमूना लें:

String str = "asdf éß";
String str2 = "asdf gh";
EncodingInfo[] info =  Encoding.GetEncodings();
foreach (EncodingInfo enc in info)
{
    System.Console.WriteLine(enc.Name + " - " 
      + enc.GetEncoding().GetByteCount(str)
      + enc.GetEncoding().GetByteCount(str2));
}

ध्यान दें कि यूनिकोड उत्तर दोनों उदाहरणों में 14 बाइट्स हैं, जबकि UTF-8 उत्तर पहले के लिए केवल 9 बाइट्स हैं, और दूसरे के लिए केवल 7 बाइट्स हैं।

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


10

मुख्य मुद्दा यह है कि एक स्ट्रिंग में एक ग्लिफ़ 32 बिट्स (एक चरित्र कोड के लिए 16 बिट्स) लेता है, लेकिन एक बाइट में केवल 8 बिट्स ही होते हैं। एक-से-एक मैपिंग मौजूद नहीं है जब तक कि आप अपने आप को स्ट्रिंग्स तक सीमित नहीं रखते हैं जिसमें केवल ASCII वर्ण हैं। System.Text.Encoding के पास एक स्ट्रिंग को बाइट में मैप करने के बहुत सारे तरीके हैं [], आपको एक चुनने की ज़रूरत है जो जानकारी के नुकसान से बचाती है और जब वह बाइट को मैप करने की आवश्यकता होती है तो अपने क्लाइंट द्वारा उपयोग करना आसान होता है [] वापस एक स्ट्रिंग पर ।

Utf8 एक लोकप्रिय एन्कोडिंग है, यह कॉम्पैक्ट है और हानिपूर्ण नहीं है।


3
UTF-8 केवल तभी कॉम्पैक्ट होता है जब आपके अधिकांश वर्ण अंग्रेजी (ASCII) वर्ण सेट में हों। यदि आपके पास चीनी अक्षरों की एक लंबी स्ट्रिंग है, तो उस स्ट्रिंग के लिए UTF-16 UTF-8 की तुलना में अधिक कॉम्पैक्ट एन्कोडिंग होगा। ऐसा इसलिए है क्योंकि UTF-8 ASCII को एनकोड करने के लिए एक बाइट का उपयोग करता है, और 3 (या शायद 4) अन्यथा।
जोएल म्यूलर

7
सच। लेकिन, अगर आप चीनी पाठ को संभालने से परिचित हैं तो आप एन्कोडिंग के बारे में कैसे नहीं जान सकते
हंस पसंत

9

उपयोग:

    string text = "string";
    byte[] array = System.Text.Encoding.UTF8.GetBytes(text);

परिणाम है:

[0] = 115
[1] = 116
[2] = 114
[3] = 105
[4] = 110
[5] = 103

OP विशेष रूप से एन्कोडिंग निर्दिष्ट नहीं करने के लिए कहता है ... "मैन्युअल रूप से एक विशिष्ट एन्कोडिंग निर्दिष्ट किए बिना"
Ferdz

8

सबसे तेज़ तरीका

public static byte[] GetBytes(string text)
{
    return System.Text.ASCIIEncoding.UTF8.GetBytes(text);
}

EDIT के रूप में मकोतोसन ने टिप्पणी की यह अब सबसे अच्छा तरीका है:

Encoding.UTF8.GetBytes(text)

8
ASCIIEncoding ..... की जरूरत नहीं है। बस Encoding.UTF8.GetBytes (पाठ) का उपयोग करना पसंद किया जाता है।
मकोतोसन

8

मैं एक विशेष बाइट को मैन्युअल रूप से निर्दिष्ट किए बिना एक स्ट्रिंग को बाइट [] में .NET (C #) में कैसे परिवर्तित करूं?

.NET में एक स्ट्रिंग UTF-16 कोड इकाइयों के अनुक्रम के रूप में पाठ का प्रतिनिधित्व करता है, इसलिए बाइट्स पहले से ही UTF-16 में मेमोरी में एन्कोडेड हैं।

मेहरदाद का जवाब

आप मेहरदाद के उत्तर का उपयोग कर सकते हैं , लेकिन यह वास्तव में एन्कोडिंग का उपयोग करता है क्योंकि चार्ट यूटीएफ -16 हैं। यह ToCharArray कहता है जो स्रोत को देखता है एक बनाता है char[]और मेमोरी को सीधे इसे कॉपी करता है। फिर यह डेटा को एक बाइट सरणी में कॉपी करता है जिसे आवंटित भी किया गया है। तो हुड के तहत यह अंतर्निहित बाइट्स को दो बार कॉपी कर रहा है और एक चार सरणी आवंटित करता है जो कॉल के बाद उपयोग नहीं किया जाता है।

टॉम ब्लोडेट का जवाब

टॉम ब्लोडेट का जवाब मेहरदाद की तुलना में 20-30% अधिक तेज है क्योंकि यह एक चार सरणी को आवंटित करने और बाइट्स की प्रतिलिपि बनाने के मध्यवर्ती चरण को छोड़ देता है, लेकिन इसके लिए आपको /unsafeविकल्प के साथ संकलन करने की आवश्यकता होती है। यदि आप पूरी तरह से एन्कोडिंग का उपयोग नहीं करना चाहते हैं, तो मुझे लगता है कि यह जाने का रास्ता है। यदि आप अपना एन्क्रिप्शन लॉगिन fixedब्लॉक के अंदर रखते हैं , तो आपको एक अलग बाइट सरणी आवंटित करने और बाइट्स को कॉपी करने की भी आवश्यकता नहीं है।

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

क्योंकि वह करने का उचित तरीका है। stringएक अमूर्त है।

यदि आप अमान्य वर्णों के साथ 'तार' रखते हैं, तो एन्कोडिंग का उपयोग आपको परेशानी दे सकता है, लेकिन ऐसा नहीं होना चाहिए। यदि आप अमान्य अक्षरों के साथ अपने स्ट्रिंग में डेटा प्राप्त कर रहे हैं तो आप इसे गलत कर रहे हैं। आप शायद एक बाइट सरणी या एक Base64 एन्कोडिंग के साथ शुरू करने के लिए उपयोग करना चाहिए।

यदि आप उपयोग करते हैं System.Text.Encoding.Unicode, तो आपका कोड अधिक लचीला होगा। जिस सिस्टम पर आपका कोड चल रहा होगा, उसकी समाप्ति के बारे में आपको चिंता करने की ज़रूरत नहीं है । आपको चिंता करने की ज़रूरत नहीं है कि सीएलआर का अगला संस्करण एक अलग आंतरिक वर्ण एन्कोडिंग का उपयोग करेगा।

मुझे लगता है कि सवाल यह नहीं है कि आप एन्कोडिंग के बारे में चिंता क्यों करना चाहते हैं, लेकिन आप इसे अनदेखा क्यों करना चाहते हैं और कुछ और उपयोग करना चाहते हैं। एन्कोडिंग का अर्थ है बाइट्स के अनुक्रम में एक स्ट्रिंग के अमूर्त का प्रतिनिधित्व करना। System.Text.Encoding.Unicodeआपको थोड़ी एंडियन बाइट ऑर्डर एन्कोडिंग देगा और हर सिस्टम पर, अब और भविष्य में भी ऐसा ही प्रदर्शन करेगा।


वास्तव में C # में एक स्ट्रिंग सिर्फ UTF-16 तक ही सीमित नहीं है। यह सच है कि इसमें 16-बिट कोड इकाइयों का वेक्टर होता है, लेकिन ये 16-बिट कोड इकाइयां मान्य UTF-16 तक सीमित नहीं होती हैं। लेकिन जैसा कि वे 16-बिट हैं, आपको उन्हें 8bit में बदलने के लिए एन्कोडिंग (बाइट ऑर्डर) की आवश्यकता होती है। एक स्ट्रिंग फिर बाइनरी कोड (जैसे एक बिटमैप छवि) सहित गैर-यूनिकोड डेटा संग्रहीत कर सकती है। इसकी व्याख्या केवल I / O और पाठ फ़ॉर्मेटर्स में UTF-16 के रूप में की जाती है जो इस तरह की व्याख्या करते हैं।
वर्डी_पी।

तो एक C # स्ट्रिंग में, आप सुरक्षित रूप से 0xFFFF या 0xFFFE जैसी कोड इकाई संग्रहीत कर सकते हैं, भले ही वे UTF-16 में गैर-वर्ण हों, और आप 0xDC00..0xDFFF में कोड इकाई द्वारा अनुसरण न किए गए एक पृथक 0xD800 को संग्रहीत कर सकते हैं (अर्थात Unpaired surrogates जो UTF-16 में अमान्य हैं)। जावास्क्रिप्ट / ECMAscript और Java में स्ट्रिंग्स पर भी यही टिप्पणी लागू होती है।
verdy_p

जब आप "GetBytes" का उपयोग करते हैं, तो निश्चित रूप से आप एन्कोडिंग निर्दिष्ट नहीं करते हैं, लेकिन आप स्ट्रिंग में स्थानीय रूप से संग्रहीत प्रत्येक कोड इकाई के लिए एक युक्ति में दो बाइट्स प्राप्त करने के लिए एक बाइट ऑर्डर मानते हैं। जब आप बाइट्स से एक नया स्ट्रिंग बनाते हैं, तो आपको एक कनवर्टर की भी आवश्यकता होती है, जरूरी नहीं कि UTF-8 से UTF-16 तक, आप हाई बाइट में अतिरिक्त 0 सम्मिलित कर सकते हैं, या दो बाइट्स पैक कर सकते हैं (MSB पहले या LSB पहले क्रम में) समान 16-बिट कोड इकाई। स्ट्रिंग्स तो 16-बिट पूर्णांक के सरणियों के लिए कॉम्पैक्ट रूप हैं। "वर्ण" के साथ संबंध एक और समस्या है, सी # में वे वास्तविक प्रकार नहीं हैं क्योंकि वे अभी भी तार के रूप में दर्शाए जाते हैं
verdy_p

7

ओपी के प्रश्न के सबसे करीब का दृष्टिकोण टॉम ब्लोडेट है, जो वास्तव में ऑब्जेक्ट में जाता है और बाइट्स को निकालता है। मैं निकटतम कहता हूं क्योंकि यह स्ट्रिंग ऑब्जेक्ट के कार्यान्वयन पर निर्भर करता है।

"Can't I simply get what bytes the string has been stored in?"

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

आप जो चाहते हैं वह एक वर्ण में प्रत्येक वर्ण के बाइट्स हैं। और यहीं पर 'एन्कोडिंग' आता है। डिफ़ॉल्ट रूप से आपको UTF-16LE मिलेगा। यदि आप राउंड ट्रिप को छोड़कर खुद बाइट्स के बारे में परवाह नहीं करते हैं, तो आप 'डिफ़ॉल्ट' सहित किसी भी एन्कोडिंग को चुन सकते हैं, और बाद में इसे वापस कन्वर्ट कर सकते हैं (मानदंड एन्कोडिंग, कोड पॉइंट्स, बग फिक्स जैसे ही पैरामीटर , चीजों की अनुमति नहीं दी गई है जैसे कि अप्रकाशित सरोगेट इत्यादि।

लेकिन क्यों जादू करने के लिए 'एन्कोडिंग' छोड़ दें? एन्कोडिंग को निर्दिष्ट क्यों नहीं किया जाता है ताकि आप जान सकें कि आपको क्या बाइट्स प्राप्त होने वाले हैं?

"Why is there a dependency on character encodings?"

एन्कोडिंग (इस संदर्भ में) का अर्थ है बाइट्स जो आपकी स्ट्रिंग का प्रतिनिधित्व करता है। स्ट्रिंग ऑब्जेक्ट के बाइट्स नहीं। आप चाहते थे कि बाइट्स स्ट्रिंग को संग्रहीत किया गया है - यह वह जगह है जहां सवाल भोलेपन से पूछा गया था। आप एक सन्निहित सरणी में स्ट्रिंग के बाइट्स चाहते थे जो स्ट्रिंग का प्रतिनिधित्व करते हैं, और सभी अन्य बाइनरी डेटा नहीं हैं जो एक स्ट्रिंग ऑब्जेक्ट हो सकते हैं।

जिसका मतलब है कि कैसे एक स्ट्रिंग संग्रहीत है अप्रासंगिक है। आप एक बाइट सरणी में बाइट्स में एक स्ट्रिंग "एनकोडेड" चाहते हैं।

मुझे टॉम ब्लोग का जवाब पसंद है क्योंकि वह आपको 'बाइट्स ऑफ द स्ट्रिंग ऑब्जेक्ट' दिशा की ओर ले गया था। हालांकि यह कार्यान्वयन पर निर्भर है, और क्योंकि वह आंतरिक पर झांक रहा है, यह स्ट्रिंग की एक प्रति पुनर्गठित करना मुश्किल हो सकता है।

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


मैंने इस बारे में अपना विचार बदल दिया है (मेहरदाद का समाधान) - यह स्ट्रिंग के बाइट्स नहीं मिल रहा है; बल्कि यह चरित्र सरणी के बाइट्स प्राप्त कर रहा है जो स्ट्रिंग से बनाया गया था। एन्कोडिंग के बावजूद, सी # में डेटा डेटापाइप एक निश्चित आकार है। यह एक सुसंगत लंबाई बाइट सरणी का उत्पादन करने की अनुमति देता है, और यह चरित्र सरणी को बाइट सरणी के आकार के आधार पर पुन: पेश करने की अनुमति देता है। तो अगर एन्कोडिंग UTF-8 थे, लेकिन सबसे बड़े utf8 मूल्य को समायोजित करने के लिए प्रत्येक चार 6 बाइट्स थे, तब भी यह काम करेगा। तो वास्तव में - चरित्र का एन्कोडिंग कोई फर्क नहीं पड़ता।

लेकिन एक रूपांतरण का उपयोग किया गया था - प्रत्येक चरित्र को एक निश्चित आकार के बॉक्स (सी # के चरित्र प्रकार) में रखा गया था। हालाँकि वह प्रतिनिधित्व क्या मायने नहीं रखता, जो तकनीकी रूप से ओपी का जवाब है। तो - अगर आप वैसे भी बदलने जा रहे हैं ... तो 'एनकोड' क्यों नहीं?


ये अक्षर रहे हैं समर्थित नहीं UTF-8 या UTF-16 या यहाँ तक कि UTF-32 से exapmle के लिए: 񩱠और (Char) 55906और (Char) 55655। तो आप गलत हो सकते हैं और मेहरदाद का जवाब बिना किसी प्रकार के एनकोडिंग का उपयोग किए बिना एक सुरक्षित रूपांतरण है।
मोजतबा रज़ाईयन

Raymon, वर्ण पहले से ही कुछ यूनिकोड मान द्वारा दर्शाए गए हैं - और सभी यूनिकोड मानों को सभी यूटीएफ द्वारा दर्शाया जा सकता है। क्या आप के बारे में बात कर रहे हैं की एक लंबी व्याख्या है? क्या वर्ण एन्कोडिंग उन दो मूल्यों (या 3 ..) में मौजूद है?
गेरार्ड ओनील

वे अमान्य वर्ण हैं जो किसी भी एन्कोडिंग श्रेणियों द्वारा समर्थित नहीं हैं। इसका मतलब यह नहीं है कि वे 100% बेकार हैं। एक कोड जो किसी भी प्रकार के स्ट्रिंग को अपने बाइट सरणी के बराबर परिवर्तित करता है, भले ही एन्कोडिंग की परवाह किए बिना एक गलत समाधान नहीं है और वांछित अवसरों पर अपने स्वयं के उपयोग हैं।
मोजतबा रेज़ियन 21

1
ठीक है, तो मुझे लगता है कि आप समस्या को नहीं समझ रहे हैं। हम जानते हैं कि यह एक यूनिकोड अनुरूप सरणी है - वास्तव में, क्योंकि यह .net है, हम जानते हैं कि यह UTF-16 है। इसलिए वे पात्र वहां मौजूद नहीं होंगे। आपने आंतरिक अभ्यावेदन के बारे में मेरी टिप्पणी को पूरी तरह से नहीं पढ़ा है। स्ट्रिंग एक ऑब्जेक्ट है, एन्कोडेड बाइट ऐरे नहीं। इसलिए मैं आपके अंतिम कथन से असहमत हूं। आप कोड को सभी यूनिकोड स्ट्रिंग्स को किसी भी UTF एन्कोडिंग में बदलना चाहते हैं। यह वही करता है जो आप चाहते हैं, सही ढंग से।
गेरार्ड ओनील

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

6

.NET में a stringको कन्वर्ट करने के लिए आप निम्न कोड का उपयोग कर सकते हैंbyte array

string s_unicode = "abcéabc";
byte[] utf8Bytes = System.Text.Encoding.UTF8.GetBytes(s_unicode);

3

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

[DllImport(
        "msvcrt.dll",
        EntryPoint = "memcpy",
        CallingConvention = CallingConvention.Cdecl,
        SetLastError = false)]
private static extern unsafe void* UnsafeMemoryCopy(
    void* destination,
    void* source,
    uint count);

public static byte[] GetUnderlyingBytes(string source)
{
    var length = source.Length * sizeof(char);
    var result = new byte[length];
    unsafe
    {
        fixed (char* firstSourceChar = source)
        fixed (byte* firstDestination = result)
        {
            var firstSource = (byte*)firstSourceChar;
            UnsafeMemoryCopy(
                firstDestination,
                firstSource,
                (uint)length);
        }
    }

    return result;
}

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

यह सिर्फ कॉल करने के लिए सुरक्षित, सरल और अधिक विश्वसनीय होगा,

System.Text.Encoding.Unicode.GetBytes()

सभी संभावना में यह समान परिणाम देगा, टाइप करना आसान है, और बाइट हमेशा कॉल के साथ गोल-यात्रा करेंगे

System.Text.Encoding.Unicode.GetString()

3

यहाँ रूपांतरण के Stringलिए मेरा असुरक्षित कार्यान्वयन है Byte[]:

public static unsafe Byte[] GetBytes(String s)
{
    Int32 length = s.Length * sizeof(Char);
    Byte[] bytes = new Byte[length];

    fixed (Char* pInput = s)
    fixed (Byte* pBytes = bytes)
    {
        Byte* source = (Byte*)pInput;
        Byte* destination = pBytes;

        if (length >= 16)
        {
            do
            {
                *((Int64*)destination) = *((Int64*)source);
                *((Int64*)(destination + 8)) = *((Int64*)(source + 8));

                source += 16;
                destination += 16;
            }
            while ((length -= 16) >= 16);
        }

        if (length > 0)
        {
            if ((length & 8) != 0)
            {
                *((Int64*)destination) = *((Int64*)source);

                source += 8;
                destination += 8;
            }

            if ((length & 4) != 0)
            {
                *((Int32*)destination) = *((Int32*)source);

                source += 4;
                destination += 4;
            }

            if ((length & 2) != 0)
            {
                *((Int16*)destination) = *((Int16*)source);

                source += 2;
                destination += 2;
            }

            if ((length & 1) != 0)
            {
                ++source;
                ++destination;

                destination[0] = source[0];
            }
        }
    }

    return bytes;
}

यह स्वीकार किए जाते हैं कि एक से अधिक तेजी से रास्ता है, भले ही यह उतना सुंदर न हो। यहाँ 10000000 से अधिक पुनरावृत्तियों पर मेरे स्टॉपवॉच बेंचमार्क हैं:

[Second String: Length 20]
Buffer.BlockCopy: 746ms
Unsafe: 557ms

[Second String: Length 50]
Buffer.BlockCopy: 861ms
Unsafe: 753ms

[Third String: Length 100]
Buffer.BlockCopy: 1250ms
Unsafe: 1063ms

इसका उपयोग करने के लिए, आपको अपनी प्रोजेक्ट बिल्ड प्रॉपर्टीज़ में "Allow Unsafe Code" पर टिक करना होगा। .NET फ्रेमवर्क 3.5 के अनुसार, इस पद्धति का उपयोग स्ट्रिंग एक्सटेंशन के रूप में भी किया जा सकता है:

public static unsafe class StringExtensions
{
    public static Byte[] ToByteArray(this String s)
    {
        // Method Code
    }
}

RuntimeHelpers.OffsetToStringData.NET के इटेनियम संस्करणों पर 8 के गुणक का मान है ? क्योंकि अन्यथा पढ़े-लिखे होने के कारण यह विफल हो जाएगा।
जॉन हैना

क्या यह आसान नहीं होगा memcpy? stackoverflow.com/a/27124232/659190
जॉडरेल

2

बस इसका उपयोग करें:

byte[] myByte= System.Text.ASCIIEncoding.Default.GetBytes(myString);

2
... और सभी पात्रों को एक छलांग के साथ 127 से अधिक का सामना करना पड़ता है। मेरी मूल भाषा में "űrvíztükrí tükörfúrógép" लिखना पूरी तरह से वैध है। वह जानकारी खो System.Text.ASCIIEncoding.Default.GetBytes("Árvíztűrő tükörfúrógép.").ToString();देगा "Árvizturo tukörfurogép."जिसे पुनर्प्राप्त नहीं किया जा सकता है। (और मैंने अभी तक एशियाई भाषाओं का उल्लेख नहीं किया है जहां आप सभी पात्रों को ढीला कर देंगे।)
mg30rg

2

स्ट्रिंग को कुछ अलग तरीकों से बाइट सरणी में परिवर्तित किया जा सकता है, निम्न तथ्य के कारण: .NET यूनिकोड का समर्थन करता है, और यूनिकोड यूटीएफ नामक कई अंतर एनकोडिंग को मानकीकृत करता है। उनके पास बाइट प्रतिनिधित्व की अलग-अलग लंबाई है, लेकिन इस अर्थ में बराबर है कि जब एक स्ट्रिंग को एन्कोड किया जाता है, तो इसे वापस स्ट्रिंग में कोडित किया जा सकता है, लेकिन यदि स्ट्रिंग को एक UTF के साथ एन्कोड किया गया है और अलग UTF की धारणा में डिकोड किया गया है तो खराब हो सकता है यूपी।

इसके अलावा, .NET गैर-यूनिकोड एन्कोडिंग का समर्थन करता है, लेकिन वे सामान्य मामले में मान्य नहीं हैं (केवल तभी मान्य होगा जब यूनिकोड कोड बिंदु का सीमित उप-सेट वास्तविक स्ट्रिंग में उपयोग किया जाता है, जैसे कि ASCII)। आंतरिक रूप से, .NET UTF-16 का समर्थन करता है, लेकिन स्ट्रीम प्रतिनिधित्व के लिए, आमतौर पर UTF-8 का उपयोग किया जाता है। यह इंटरनेट के लिए एक मानक-डी-फैक्टो भी है।

आश्चर्य की बात नहीं है, बाइट और डिसेरिएलाइज़ेशन की एक श्रृंखला में स्ट्रिंग का क्रमांकन वर्ग द्वारा समर्थित है System.Text.Encoding, जो एक सार वर्ग है; इसके व्युत्पन्न वर्ग कंक्रीट एन्कोडिंग का समर्थन करते हैं: ASCIIEncodingऔर चार System.Text.UnicodeEncodingUTF ( UTF-16 का समर्थन करता है)

रेफरी इस लिंक।

का उपयोग कर बाइट्स की एक सरणी के लिए क्रमांकन के लिए System.Text.Encoding.GetBytes। उलटा ऑपरेशन के लिए उपयोग करें System.Text.Encoding.GetChars। यह फ़ंक्शन वर्णों की एक सरणी देता है, इसलिए स्ट्रिंग प्राप्त करने के लिए, स्ट्रिंग निर्माता का उपयोग करें System.String(char[])
इस पृष्ठ को देखें।

उदाहरण:

string myString = //... some string

System.Text.Encoding encoding = System.Text.Encoding.UTF8; //or some other, but prefer some UTF is Unicode is used
byte[] bytes = encoding.GetBytes(myString);

//next lines are written in response to a follow-up questions:

myString = new string(encoding.GetChars(bytes));
byte[] bytes = encoding.GetBytes(myString);
myString = new string(encoding.GetChars(bytes));
byte[] bytes = encoding.GetBytes(myString);

//how many times shall I repeat it to show there is a round-trip? :-)

2

यह निर्भर करता है कि आपको बाइट्स के लिए क्या चाहिए

ऐसा इसलिए है, क्योंकि टायलर ने कहा था , "स्ट्रिंग्स शुद्ध डेटा नहीं हैं। उनके पास जानकारी भी है ।" इस मामले में, जानकारी एक एन्कोडिंग है जिसे तब बनाया गया था जब स्ट्रिंग बनाया गया था।

यह मानते हुए कि आपके पास एक स्ट्रिंग में संग्रहीत बाइनरी डेटा (पाठ के बजाय) है

यह ओपी की अपने सवाल पर की गई टिप्पणी पर आधारित है, और अगर मैं ओपी के उपयोग के मामले में संकेत समझता हूं तो यह सही सवाल है।

उपरोक्त वर्णित एन्कोडिंग के कारण स्ट्रिंग्स में बाइनरी डेटा संग्रहीत करना संभवतः गलत दृष्टिकोण है! जो भी प्रोग्राम या लाइब्रेरी उस बाइनरी डेटा stringको एक byte[]सरणी के बजाय संग्रहीत करता है ( जो कि अधिक उपयुक्त होगा) शुरू होने से पहले ही लड़ाई हार गया है। यदि वे आपको बाइट्स को REST अनुरोध / प्रतिक्रिया या कुछ भी भेज रहे हैं जो स्ट्रिंग्स को प्रसारित करना होगा , तो बेस 64 सही दृष्टिकोण होगा।

यदि आपके पास अज्ञात एन्कोडिंग के साथ एक पाठ स्ट्रिंग है

इस गलत सवाल का जवाब हर किसी ने गलत तरीके से दिया।

यदि स्ट्रिंग के रूप में अच्छा लग रहा है, बस एक एन्कोडिंग उठाओ (अधिमानतः एक UTF के साथ शुरू होता है), इसी System.Text.Encoding.???.GetBytes()फ़ंक्शन का उपयोग करें , और बताएं कि आप जो भी बाइट देते हैं, वह आपको दिया गया है।


2

यह पूछे जाने पर कि आप बाइट्स के साथ क्या करने का इरादा रखते हैं, आपने जवाब दिया :

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

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

  • आपको एक अलग भाषा या रनटाइम में कार्यान्वित प्रक्रिया के साथ संवाद करने की आवश्यकता हो सकती है। (इसमें उदाहरण के लिए किसी अन्य मशीन पर चलने वाला सर्वर और एक स्ट्रिंग को जावास्क्रिप्ट ब्राउज़र क्लाइंट में भेजना शामिल हो सकता है।)
  • कार्यक्रम को भविष्य में एक अलग भाषा या रनटाइम में फिर से लागू किया जा सकता है।
  • .NET कार्यान्वयन स्ट्रिंग्स के आंतरिक प्रतिनिधित्व को बदल सकता है। आप सोच सकते हैं कि यह बहुत दूर की आवाज़ है, लेकिन यह वास्तव में जावा 9 में मेमोरी उपयोग को कम करने के लिए हुआ था । कोई कारण नहीं है। .NET सूट का पालन नहीं कर सकता है।स्कीट का सुझाव है कि यूटीएफ -16 शायद इष्टतम नहीं है, आज इमोजी के उदय और यूनिकोड के अन्य ब्लॉकों को 2 बाइट्स की आवश्यकता है और साथ ही साथ प्रतिनिधित्व करने की संभावना बढ़ जाती है, जिससे भविष्य में आंतरिक प्रतिनिधित्व बदल सकता है।

संवाद करने के लिए (या तो पूरी तरह से असमान प्रक्रिया के साथ या भविष्य में उसी कार्यक्रम के साथ), आपको इसके साथ काम करने की गलती को कम करने या गलती से बग बनाने के लिए अपने प्रोटोकॉल को कड़ाई से परिभाषित करने की आवश्यकता है । .NET के आंतरिक प्रतिनिधित्व के आधार पर एक सख्त, स्पष्ट या निरंतर परिभाषा की गारंटी नहीं है। एक मानक एन्कोडिंग है एक सख्त परिभाषा है कि भविष्य में आप असफल नहीं होंगे।

दूसरे शब्दों में, आप स्थिरता के लिए अपनी आवश्यकता को पूरा नहीं कर सकते एन्कोडिंग निर्दिष्ट किए बिना ।

आप निश्चित रूप से कर सकते हैं से यूटीएफ -16 का उपयोग करना चुन हैं यदि आप पाते हैं कि आपकी प्रक्रिया बेहतर प्रदर्शन करती है क्योंकि .NET इसे आंतरिक रूप से या किसी अन्य कारण से उपयोग करता है, लेकिन आपको उस कोडिंग को स्पष्ट रूप से चुनने और अपने कोड के आधार पर स्पष्ट रूप से रूपांतरण करने की आवश्यकता है .NET के आंतरिक कार्यान्वयन पर।

इसलिए एक एन्कोडिंग चुनें और इसका उपयोग करें:

using System.Text;

// ...

Encoding.Unicode.GetBytes("abc"); # UTF-16 little endian
Encoding.UTF8.GetBytes("abc")

जैसा कि आप देख सकते हैं, यह वास्तव में कम कोड भी है जो केवल अपने स्वयं के पाठक / लेखक विधियों को लागू करने की तुलना में एन्कोडिंग ऑब्जेक्ट्स में निर्मित उपयोग करने के लिए है।


1

दो तरीके:

public static byte[] StrToByteArray(this string s)
{
    List<byte> value = new List<byte>();
    foreach (char c in s.ToCharArray())
        value.Add(c.ToByte());
    return value.ToArray();
}

तथा,

public static byte[] StrToByteArray(this string s)
{
    s = s.Replace(" ", string.Empty);
    byte[] buffer = new byte[s.Length / 2];
    for (int i = 0; i < s.Length; i += 2)
        buffer[i / 2] = (byte)Convert.ToByte(s.Substring(i, 2), 16);
    return buffer;
}

मैं नीचे से ऊपर की ओर एक बार उपयोग करता हूं, उन्हें गति के लिए बेंचमार्क नहीं किया है।


4
मल्टीबाइट पात्रों के बारे में क्या?
एगेल कुरियन

c.ToByte () निजी है: S
खोडोर

@AgnelKurian Msdn का कहना है कि "यह विधि एक अहस्ताक्षरित बाइट मान लौटाती है, जो इसमें पास किए गए चार के सांख्यिक कोड का प्रतिनिधित्व करता है। .NET फ्रेमवर्क में, एक चार ऑब्जेक्ट 16-बिट मान है। इसका मतलब यह है कि यह विधि वापसी के लिए उपयुक्त है। ASCII वर्ण श्रेणी या यूनिकोड C0 नियंत्रण और मूल लैटिन, और C1 नियंत्रण और लैटिन -1 अनुपूरक श्रेणियों में वर्णों के संख्यात्मक कोड, U + 0000 से U + 00FF तक। "
mg30rg

1
bytes[] buffer = UnicodeEncoding.UTF8.GetBytes(string something); //for converting to UTF then get its bytes

bytes[] buffer = ASCIIEncoding.ASCII.GetBytes(string something); //for converting to ascii then get its bytes
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.