शून्य-टर्मिनेट बाइट सरणी को स्ट्रिंग में कैसे बदलें?


502

मुझे डेटा [100]byteका एक गुच्छा स्थानांतरित करने के लिए पढ़ने की आवश्यकता है string

क्योंकि सभी नहीं stringठीक 100 वर्ण लंबे हैं, शेष भाग s के byte arrayसाथ गद्देदार है 0

यदि मैं इसके द्वारा परिवर्तित [100]byteकरता हूं string:, string(byteArray[:])टेलिंग 0एस को ^@^@एस के रूप में प्रदर्शित किया जाता है ।

सी में stringपर समाप्त हो जाएंगे 0, तो मुझे आश्चर्य है कि सबसे अच्छा तरीका यह कन्वर्ट करने के लिए क्या byte arrayकरने के लिए stringGolang में।


3
@ AndréLaszlo: खेल के मैदान में ^@नहीं दिखा, लेकिन यह वहाँ होता अगर आप इसे टर्मिनल या कुछ इसी तरह का परीक्षण करते। इसका कारण, यह है कि गो बाइट्स सरणी को स्ट्रिंग में परिवर्तित करना बंद नहीं करता है जब यह पाता है कि एक 0. len(string(bytes))आपके उदाहरण में 5 है और 1 नहीं है। यह आउटपुट फ़ंक्शन पर निर्भर करता है, चाहे स्ट्रिंग पूरी तरह से (शून्य के साथ) मुद्रित हो या नहीं।
निमो

8
Http प्रतिक्रिया निकाय के लिए, का उपयोग करें string(body)
इवान चाऊ

जवाबों:


513

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

s := string(byteArray[:n])

पूर्ण स्ट्रिंग को परिवर्तित करने के लिए इसका उपयोग किया जा सकता है:

s := string(byteArray[:len(byteArray)])

यह इसके बराबर है:

s := string(byteArray)

यदि किसी कारण से आप नहीं जानते हैं n, तो आप bytesइसे खोजने के लिए पैकेज का उपयोग कर सकते हैं , यह मानते हुए कि आपके इनपुट में एक अशक्त चरित्र नहीं है।

n := bytes.Index(byteArray, []byte{0})

या जैसा कि icza ने बताया है, आप नीचे दिए गए कोड का उपयोग कर सकते हैं:

n := bytes.IndexByte(byteArray, 0)

2
मुझे पता है कि मुझे एक साल देर हो चुकी है, लेकिन मुझे यह उल्लेख करना चाहिए कि अधिकांश विधियाँ पढ़े गए बाइट्स की संख्या को वापस कर देती हैं। उदाहरण के लिए, बाइनरी.हेड () एक [32] बाइट में पढ़ सकता है, लेकिन आप नहीं जानते कि आपने सभी 32 बाइट्स भरे हैं या नहीं।
एरिक लेगरग्रेन

7
आपको 1 बाइट वाले बाइट स्लाइस के बजाय bytes.IndexByte()एकल के लिए खोज करना चाहिए । bytebytes.Index()
icza

56
वास्तव में स्ट्रिंग (बाइटएयरे) भी करेगा और एक स्लाइस निर्माण को बचाएगा
थ्रो_सेक्सुअलिटी_ट_यौ

3
हालांकि, यह स्पष्ट है कि यह कुछ बाइट्स का एक क्रम कास्टिंग कर रहा है जो उम्मीद है कि एक वैध UTF-8 स्ट्रिंग है (और नहीं कहे, लैटिन -1 इत्यादि, या कुछ विकृत UTF-8 अनुक्रम)। जब आप कास्ट करेंगे तब गो आपके लिए यह चेक नहीं करेगा।
कैमरून केर

क्या होगा यदि आपका बाइट सरणी रिवर्स ऑर्डर उर्फ ​​थोड़ा एंडियन में है?
सर

374

व्हाट अबाउट?

s := string(byteArray[:])

3
सुनिश्चित करने के लिए बाइट सरणी में परिवर्तित करने का सबसे साफ तरीका। मुझे आश्चर्य है कि अगर तार। यह नल बाइट्स को हटाने में मदद करेगा? golang.org/pkg/strings/#example_Trim
andyvanee

24
यह प्रश्न विशेष रूप से कहता है कि string(byteArray[:])इसमें ^@वर्ण शामिल हैं
रॉबर्ट

24
इससे क्या फर्क पड़ता है string(byteArray)? आपको सरणी का उपयोग करके कॉपी करने की आवश्यकता क्यों है [:]?
रॉबर्ट ज़रेम्बा

7
@RobertZaremba> एक स्ट्रिंग प्रभाव में है बाइट्स का केवल एक टुकड़ा। आप बाइट एरे को सीधे स्ट्रिंग में नहीं बदल सकते, इसलिए पहले स्लाइस फिर स्ट्रिंग।
फेरहट इलामास

3
@RobertZaremba बाइट स्लाइस के [:]लिए, आपको बाइट सरणियों के लिए, जोड़ने की जरूरत नहीं है , आप करते हैं।
आकर्षित LeSueur

68

सरलीकृत समाधान:

str := fmt.Sprintf("%s", byteArray)

मुझे यकीन नहीं है कि हालांकि यह कितना अच्छा है।


17

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

package main

import "fmt"

func CToGoString(c []byte) string {
    n := -1
    for i, b := range c {
        if b == 0 {
            break
        }
        n = i
    }
    return string(c[:n+1])
}

func main() {
    c := [100]byte{'a', 'b', 'c'}
    fmt.Println("C: ", len(c), c[:4])
    g := CToGoString(c[:])
    fmt.Println("Go:", len(g), g)
}

आउटपुट:

C:  100 [97 98 99 0]
Go: 3 abc

8

निम्नलिखित कोड '\ 0' की तलाश में है, और प्रश्न की मान्यताओं के तहत सरणी को सभी गैर - '0' से पहले के सभी '0' के रूप में क्रमबद्ध माना जा सकता है। यदि डेटा के भीतर सरणी में '\ 0' हो सकता है तो यह धारणा धारण नहीं करेगी।

बाइनरी खोज का उपयोग करके पहले शून्य-बाइट का स्थान ढूंढें, फिर स्लाइस करें।

आप इस तरह शून्य बाइट पा सकते हैं:

package main

import "fmt"

func FirstZero(b []byte) int {
    min, max := 0, len(b)
    for {
        if min + 1 == max { return max }
        mid := (min + max) / 2
        if b[mid] == '\000' {
            max = mid
        } else {
            min = mid
        }
    }
    return len(b)
}
func main() {
    b := []byte{1, 2, 3, 0, 0, 0}
    fmt.Println(FirstZero(b))
}

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


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

@peterSO आप सही हैं, और वास्तव में इसे कभी भी क्रमबद्ध नहीं किया जाता है क्योंकि यह सार्थक नामों के एक समूह का प्रतिनिधित्व करता है।
डेरिक जांग

3
यदि सभी अशक्त बाइट्स स्ट्रिंग के अंत में एक द्विआधारी खोज कार्य करते हैं।
पॉल हैंकिन

6
मुझे समझ में नहीं आता है। कोड संकलित करता है और सही है, यह मानते हुए कि स्ट्रिंग में अंत को छोड़कर no \ 0 है। कोड की खोज \ 0 के लिए है, और प्रश्न की मान्यताओं के तहत सरणी को 'क्रमबद्ध' माना जा सकता है, क्योंकि सभी गैर- \ 0 पूर्ववर्ती सभी \ 0 से पहले हैं और यह सभी कोड जाँच रहा है। यदि डाउनवोटर्स एक उदाहरण इनपुट प्राप्त कर सकते हैं जिस पर कोड काम नहीं करता है, तो मैं उत्तर हटा दूंगा।
पॉल हैंकिन

1
यदि इनपुट है तो गलत परिणाम देता है []byte{0}। इस मामले में FirstZero()लौटना चाहिए 0ताकि स्लाइसिंग परिणाम हो "", लेकिन इसके बजाय यह रिटर्न 1और स्लाइसिंग परिणाम में "\x00"
icza

3

जब आपको सरणी में गैर-शून्य बाइट्स की सही लंबाई नहीं पता है, तो आप इसे पहले ट्रिम कर सकते हैं:

स्ट्रिंग (बाइट्स। श्रीमति (गिरफ्तार, "\ x00"))


1
a) bytes.Trimएक स्लाइस लेता है, एक सरणी नहीं ( arr[:]यदि आपको गिरफ्तार करना है तो वास्तव में एक [100]byteप्रश्न के रूप में आवश्यक है)। बी) bytes.Trimयहाँ उपयोग करने के लिए गलत कार्य है। इनपुट के लिए []byte{0,0,'a','b','c',0,'d',0}यह "cc" के बजाय "abc \ x00d" लौटाएगा। पहले से ही एक सही उत्तर है जो उपयोग करता है bytes.IndexByte, पहला शून्य बाइट खोजने का सबसे अच्छा तरीका है।
डेव सी

1

यह क्यों नहीं?

bytes.NewBuffer(byteArray).String()

1
क्योंकि क) प्रश्न कहता है कि एक सरणी इतनी है कि आपको इसकी आवश्यकता होगी byteArray[:]क्योंकि bytes.NewBufferएक लेता है []byte; ख) प्रश्न में कहा गया है कि सरणी में शून्य शून्य है जिससे आप निपटते नहीं हैं; c) यदि इसके बजाय आपका वेरिएबल a []byte(आपकी लाइन कंप्लीट करने का एकमात्र तरीका है) तो आपकी लाइन सिर्फ एक स्लो तरीका है string(v)
डेव सी

1

केवल प्रदर्शन ट्यूनिंग के लिए उपयोग करें।

package main

import (
    "fmt"
    "reflect"
    "unsafe"
)

func BytesToString(b []byte) string {
    return *(*string)(unsafe.Pointer(&b))
}

func StringToBytes(s string) []byte {
    return *(*[]byte)(unsafe.Pointer(&s))
}

func main() {
    b := []byte{'b', 'y', 't', 'e'}
    s := BytesToString(b)
    fmt.Println(s)
    b = StringToBytes(s)
    fmt.Println(string(b))
}

1
-1: निश्चित नहीं है कि यह एक गंभीर जवाब है, लेकिन आप लगभग निश्चित रूप से प्रतिबिंब और असुरक्षित कोड को स्ट्रिंग के लिए बाइट स्लाइस में परिवर्तित नहीं करना चाहते हैं
ऑस्टिन हाइड

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

संपादित किया गया है, क्योंकि यह सूचक उपयोग के खिलाफ है (इसका प्रत्यक्ष कास्टिंग के समान व्यवहार है, दूसरे शब्दों में परिणाम कचरा एकत्र नहीं किया जाएगा)। पैराग्राफ (6) golang.org/pkg/unsafe/#Pointer
Laevus Dexter

0
  • पढ़ने के लिए सरणियों के बजाय स्लाइस का उपयोग करें। उदाहरण के लिए io.Readerएक टुकड़ा स्वीकार करता है, एक सरणी नहीं।

  • शून्य पैडिंग के बजाय स्लाइसिंग का उपयोग करें।

उदाहरण:

buf := make([]byte, 100)
n, err := myReader.Read(buf)
if n == 0 && err != nil {
        log.Fatal(err)
}

consume(buf[:n]) // consume will see exact (not padded) slice of read data

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

1
ओह, तो लम्बाई मान का उपयोग करके बाइट सरणी को स्लाइस करें s := a[:n]या s := string(a[:n])यदि आपको एक स्ट्रिंग की आवश्यकता है। यदि nसीधे उपलब्ध नहीं है, तो इसकी गणना की जानी चाहिए, जैसे कि डैनियल सुझाव के अनुसार बफर (सरणी) में एक विशिष्ट / शून्य बाइट की तलाश कर रहा है।
zzzz

0

मैंने कई बार कुछ तरीके आजमाए जिनसे मुझे घबराहट हुई:

रनटाइम त्रुटि: स्लाइस सीमा से बाहर।

लेकिन यह आखिरकार काम कर गया।

string(Data[:])


3
यह बहुत जानकारी नहीं जोड़ता है, और अनिवार्य रूप से 2013 से उत्तर दोहराता है: stackoverflow.com/a/18615786/349333
जोकेम शुल्लेनोपॉपर

0

हालांकि बहुत अच्छा नहीं है, केवल पठनीय समाधान है

  //split by separator and pick the first one. 
  //This has all the characters till null excluding null itself.
  retByteArray := bytes.Split(byteArray[:], []byte{0}) [0]

  // OR 

  //If you want a true C-like string including the null character
  retByteArray := bytes.SplitAfter(byteArray[:], []byte{0}) [0]

सी-स्टाइल बाइट सरणी के लिए पूर्ण उदाहरण:

package main

import (
    "bytes"
    "fmt"
)

func main() {
    var byteArray = [6]byte{97,98,0,100,0,99}

    cStyleString := bytes.SplitAfter(byteArray[:],  []byte{0}) [0]
    fmt.Println(cStyleString)
}

नल को छोड़कर गो स्टाइल स्ट्रिंग होने का पूर्ण उदाहरण:

package main

import (
    "bytes"
    "fmt"
)

func main() {
    var byteArray = [6]byte{97,98,0,100,0,99}

    goStyleString := string( bytes.Split(byteArray[:],  []byte{0}) [0] )
    fmt.Println(goStyleString)
}

यह बाइट्स के टुकड़े का एक टुकड़ा आवंटित करता है। इसलिए परफॉर्मेंस पर ध्यान रखें अगर इसका ज्यादा या बार-बार इस्तेमाल किया जाए।


-1

यहाँ बाइट सरणी को स्ट्रिंग में संपीड़ित करने के लिए कोड है

package main

import (
    "fmt"
)

func main() {
    byteArr := [100]byte{'b', 'y', 't', 'e', 's'}
    firstHalf := ToString(byteArr)
    fmt.Println("Bytes to str", string(firstHalf))
}
func ToString(byteArr [100]byte) []byte {
    arrLen := len(byteArr)
    firstHalf := byteArr[:arrLen/2]
    secHalf := byteArr[arrLen/2:]
    for {
        // if the first element is 0 in secondHalf discard second half
        if len(secHalf) != 0 && secHalf[0] == 0 {
            arrLen = len(firstHalf)
            secHalf = firstHalf[arrLen/2:]
            firstHalf = firstHalf[:arrLen/2]
            continue
        } else {
            for idx := 0; len(secHalf) > idx && secHalf[idx] != 0; idx++ {
                firstHalf = append(firstHalf, secHalf[idx])
            }
        }
        break
    }
    return firstHalf
}

-2

यहाँ तेजी से तरीका है:

resp, _ := http.Get("https://www.something.com/something.xml")
bytes, _ := ioutil.ReadAll(resp.Body)
resp.Body.Close()
fmt.Println(string(bytes)) //just convert with string() function

अगली बार पहले प्रश्न (और मौजूदा उत्तर) पढ़ें। (इसके अलावा, यदि आप वास्तव में एक बाइट स्लाइस को प्रिंट करना चाहते fmtहैं fmt.Printf("%s", bytes)तो इसका उपयोग करने की तुलना में तेज़ है string(bytes))।
डेव सी

-7

मैं जब एक पुनरावर्ती समाधान के साथ।

func CToGoString(c []byte, acc string) string {

    if len(c) == 0 {
        return acc
    } else {
        head := c[0]
        tail := c[1:]
        return CToGoString(tail, acc + fmt.Sprintf("%c", head))
    }
}

func main() {
    b := []byte{some char bytes}
    fmt.Println(CToGoString(b, ""))
}

आप एक पुनरावर्ती समाधान क्यों पसंद करते हैं?
पेट्रोएस

परीक्षण मामले fmt.Println(CToGoString([]byte("ctogo\x00\x00"), "") == "ctogo")को प्रिंट करना चाहिए true, यह प्रिंट करता है false
पेट्रोसो

1
सवाल पूछता है कि सबसे अच्छा तरीका क्या है । यह उतना ही बुरा है जितना कि यह मिल सकता है: समझने में कठिन और बहुत धीमा, यह भी एक कन्वर्ट नहीं करता [100]byteहै []byte, लेकिन '\x00'बाइट्स को बंद नहीं करता है । स्वीकृत उत्तर की गति की तुलना में इसकी गति (इनपुट पर निर्भर करती है) परिमाण के कई क्रमों से धीमी होती है।
icza
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.