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


502

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

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

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

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


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.