0으로 끝나는 바이트 배열을 문자열로 변환하는 방법은 무엇입니까?


502

[100]byte많은 string데이터 를 전송 하려면 읽어야 합니다 .

모든 strings의 길이가 정확히 100자인 것은 아니기 때문에 의 나머지 부분은 s byte array로 채워집니다 0.

내가 변환하면 [100]bytestring의해 : string(byteArray[:])의 미행 0들로 표시됩니다 ^@^@의.

C에서이 string해지됩니다 0, 그래서 나는이를 변환하는 가장 좋은 방법은 무엇 궁금 byte arraystringGolang에서.


3
@ AndréLaszlo : 놀이터에서는 ^@표시되지 않지만 터미널이나 비슷한 곳에서 테스트하면 거기에 있었을 것입니다. 그 이유는 Go가 0 len(string(bytes))을 찾을 때 바이트 배열을 문자열로 변환하는 것을 멈추지 않기 때문입니다.이 예에서 5는 1이 아니라 5입니다. 문자열이 완전히 (0으로) 인쇄되었는지 여부에 따라 출력 함수에 따라 다릅니다. 또는 아닙니다.
nemo

8
http 응답 본문에는을 사용하십시오 string(body).
Ivan Chau

답변:


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
나는 1 년 늦었다는 것을 알고 있지만 대부분의 방법은 읽은 바이트 수를 반환 한다고 언급해야합니다 . 예를 들어 binary.Read ()는 [32] 바이트로 읽을 수 있지만 32 바이트를 모두 채웠는지 여부는 알 수 없습니다.
에릭 라거 그렌

7
1 바이트를 포함하는 바이트 슬라이스 대신 bytes.IndexByte()단일 검색을 사용해야합니다 . bytebytes.Index()
icza

56
실제로 string (byteArray)도 슬라이스 생성을 저장합니다
throws_exceptions_at_you

3
그냥 분명하지만 것으로,이 무언가에 일련의 바이트 캐스팅되는 희망 (라틴 1 등을 말을하지, 또는 일부 잘못된 UTF-8 시퀀스) 유효한 UTF-8 문자열입니다. 시전 할 때 Go에서이를 확인하지 않습니다.
Cameron Kerr

바이트 배열이 리틀 엔디안 역순이면 어떨까요?
Sir

374

이건 어떤가요?

s := string(byteArray[:])

3
바이트 배열을 변환하는 가장 확실한 방법입니다. strings.Trim이 null 바이트를 제거하는 데 도움이되는지 궁금합니다. golang.org/pkg/strings/#example_Trim
andyvanee

24
질문은 구체적으로 문자 가 string(byteArray[:])포함되어 있다고 말합니다^@
Robert

24
차이점은 string(byteArray)무엇입니까? ?를 사용하여 배열을 복사해야하는 이유는 무엇 [:]입니까?
Robert Zaremba 12

7
@RobertZaremba> 문자열은 사실상 읽기 전용 바이트 조각입니다. 바이트 배열을 문자열로 직접 변환 할 수 없으므로 먼저 슬라이스 한 다음 문자열입니다.
ferhat elmas

3
@RobertZaremba 바이트 슬라이스의 [:]경우 바이트 배열의 경우을 추가 할 필요가 없습니다 .
Drew 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'을 포함 할 수 있으면이 가정은 유지되지 않습니다.

이진 검색을 사용하여 첫 번째 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))
}

특히 대부분의 문자열이 짧은 경우 바이트 배열을 순전히 스캔하여 0 바이트를 찾는 것이 더 빠를 수 있습니다.


8
코드가 컴파일되지 않으며 코드가 작동하더라도 작동하지 않습니다. 이진 검색 알고리즘은 정렬 된 배열 내에서 지정된 값의 위치를 ​​찾습니다. 배열이 반드시 정렬 될 필요는 없습니다.
peterSO

@peterSO 당신이 옳고, 실제로 의미있는 이름을 나타 내기 때문에 결코 분류되지 않습니다.
데릭 장

3
모든 널 바이트가 문자열의 끝에 있으면 이진 검색이 작동합니다.
Paul Hankin 2012 년

6
다운 보트를 이해하지 못합니다. 문자열에 끝을 제외하고 \ 0이 없다고 가정하면 코드가 컴파일되고 정확합니다. 코드는 \ 0을 찾고 질문의 가정하에 배열은 '0'이 아닌 모든 것이 모든 \ 0보다 우선하고 그것이 모든 코드를 확인하기 때문에 '정렬'된 것으로 간주 될 수 있습니다. downvoter가 코드가 작동하지 않는 예제 입력을 찾을 수 있다면 답을 제거하겠습니다.
Paul Hankin

1
입력이 인 경우 잘못된 결과를 제공합니다 []byte{0}. 이 경우에는 슬라이싱 결과가 FirstZero()반환 0될 때 반환해야 ""하지만 대신 결과가 반환 1됩니다 "\x00".
icza

3

배열에서 0이 아닌 바이트의 정확한 길이를 모르는 경우 먼저 트리밍 할 수 있습니다.

문자열 (bytes.Trim (arr, "\ x00"))


1
a) bytes.Trim배열이 아닌 슬라이스를 사용 arr[:]합니다 (arr이 실제로 [100]byte질문 상태 인 경우 필요 합니다 ). b) bytes.Trim여기서 사용하는 잘못된 기능입니다. 입력 []byte{0,0,'a','b','c',0,'d',0}의 경우 ""대신 "abc \ x00d"를 반환합니다. c) bytes.IndexByte첫 번째 0 바이트를 찾는 가장 좋은 방법 인을 사용하는 정답이 이미 있습니다.
Dave C

1

왜 안돼?

bytes.NewBuffer(byteArray).String()

1
문제는 당신이 필요로하는 것에 있도록 배열을 말한다)을하기 때문에 byteArray[:]이후 bytes.NewBuffer걸립니다 []byte; b) 질문에 따르면 배열에 처리하지 않는 후행 0이 있습니다. c) 대신 변수가 []byte(라인을 컴파일하는 유일한 방법) 인 경우 라인은 느린 수행 방법입니다 string(v).
Dave C

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 : 이것이 심각한 답변인지 확실하지 않지만, 바이트 슬라이스를 문자열로 변환하기 위해 리플렉션 및 안전하지 않은 코드를 호출하지는 않을 것입니다.
Austin Hyde

1
경고 : 안전하지 않은 바이트 슬라이스를 변환하여 string나중에 바이트 슬라이스를 수정하면 심각한 영향을 미칠 수 있습니다. stringGo의 값은 전체 Go 런타임 및 라이브러리가 빌드되는 불변으로 정의됩니다. 이 경로를 따라 가면 가장 신비한 버그와 런타임 오류의 중간으로 자신을 순간 이동시킵니다.
icza

이것은 포인터 사용에 대한 것이 아니기 때문에 편집되었습니다 (직접 캐스팅과 동일한 동작을합니다. 즉, 결과는 가비지 수집되지 않습니다).
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

데이터는 다른 사람과 다른 C 언어로 작성되었으므로 읽을 수만 있으므로 작성 방식을 제어 할 수 없습니다.
데릭 장

1
그런 다음 길이 값을 사용 s := a[:n]하거나 s := string(a[:n])문자열이 필요한 경우 바이트 배열을 슬라이스하십시오 . 경우 n바로 사용할 수없는 것이 다니엘 있듯이 버퍼 (어레이)의 특정 / 제로 바이트를 찾음으로써, 예를 산출해야한다.
zzzz

0

공황 상태에 빠졌을 때 몇 가지 방법을 시도했습니다.

런타임 오류 : 슬라이스 범위가 범위를 벗어났습니다.

그러나 이것은 마침내 효과가있었습니다.

string(Data[:])


3
이것은 많은 정보를 추가하지 않으며 본질적으로 2013 년의 대답을 반복합니다 : stackoverflow.com/a/18615786/349333 .
Jochem Schulenklopper

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]

C 스타일 바이트 배열을 갖는 전체 예 :

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)
}

null을 제외한 go 스타일 문자열을 갖는 전체 예 :

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).
Dave C

-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, ""))
}

왜 재귀 솔루션을 좋아합니까?
peterSO

테스트 케이스 fmt.Println(CToGoString([]byte("ctogo\x00\x00"), "") == "ctogo")가 인쇄 true되고 인쇄 false됩니다.
peterSO

1
질문은 가장 좋은 방법을 묻습니다 . 이것은 얻을 수있는 불량과 같습니다 이해하기 매우 느린, 또한이 변환하지 않습니다 열심히 [100]byte하지만,을 []byte, 오프 제거하지 않는 '\x00'바이트. 허용되는 답변의 속도와 비교하여 속도 (입력에 따라 다름)가 여러 배 더 느립니다.
icza
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.