Microsoft MVP성태의 닷넷 이야기
글쓴 사람
정성태 (techsharer at outlook.com)
홈페이지
첨부 파일
 
(연관된 글이 2개 있습니다.)

Golang - (문자가 아닌) 바이트 위치를 반환하는 strings.IndexRune 함수

golang의 경우 string 타입이 내부적으로 utf-8 인코딩을 유지하고 있는데요, 따라서 한글은 한 문자에 대해 3바이트의 공간을 차지합니다.

가령, 다음과 같이 문자열을 열거하는 경우,

val := "테스트1"

for i, ch := range val {
    fmt.Printf("%d - %c\n", i, ch)
}
/* 출력 결과
0 - 테
3 - 스
6 - 트
9 - 1
*/

글자는 하나씩 매핑이 되지만, 인덱스는 0, 3, 6, 9와 같이 나옵니다. 혹은 다음과 같이 열거하게 되면,

for i:=0; i < len(val); i ++ {
    fmt.Printf("%d - %c\n", i, val[i])
}
/* 출력 결과
0 - í
1 - 

2 - Œ
3 - ì
4 - Š
5 - ¤
6 - í
7 - Š
8 - ¸
9 - 1
10
*/

(대부분의 경우에서) 원치 않는 결과를 얻게 됩니다. 이러한 불균형은 rune 타입을 이용하는 것으로 해결할 수 있습니다.

val := "테스트1"

runeVal := []rune(val)

for i, ch := range runeVal {
    fmt.Printf("%d - %c\n", i, ch)
}
/* 출력 결과
0 - 테
1 - 스
2 - 트
3 - 1
*/

fmt.Printf("len(val) == %d\n", utf8.RuneCountInString(val)) // len(val) == 4

여기서, 특정 문자를 찾는 것을 해볼까요? 이를 위해 golang에서는 strings.Index와 strings.IndexRune을 제공합니다.

fmt.Printf("%d\n", strings.IndexRune(val, '1'))
fmt.Printf("%d\n", strings.Index(val, "1"))

/* 출력 결과
9
9
*/

그런데, 보다시피 출력 결과가 byte 기준의 index만을 반환하고 있습니다. 즉, 위의 결과에서 3이 나올 수 있는 Index 함수가 없는 것입니다. 이로 인해 [] rune을 열거하는 for 루프 내에서 IndexRune 함수를 쓰는 것이 매우 애매해집니다.

val := "테스트1"

runeVal := []rune(val)

for i, ch := range runeVal {
  // pos는 바이트 메모리의 위치이므로 runeVal의 위치와 무관
  // 또한 val[i:]도 바이트를 기준으로 한 위치이므로 runeVal의 index와 무관
  pos := strings.IndexRune(val[i:], '1')
}

사실 이를 위해 가장 좋은 방법은 [] rune 타입에서 Index를 제공하는 것인데 현재는 이를 제공하지 않으므로 그냥 만들어 써야 합니다.

How found offset index a string in rune using go
; https://stackoverflow.com/questions/41956391/how-found-offset-index-a-string-in-rune-using-go

val := "테스트1"

runeVal := []rune(val)

fmt.Printf("%d\n", search(runeVal, "i")) // -1
fmt.Printf("%d\n", search(runeVal, "1")) // 3

func search(text []rune, what string) int {
    whatRunes := []rune(what)

    for i := range text {
        found := true
        for j := range whatRunes {
            if text[i+j] != whatRunes[j] {
                found = false
                break
            }
        }

        if found {
            return i
        }
    }
    return -1
}




기타 또 한 가지 언급하자면, go 언어의 문자열 취급이 C/C++의 전통적인 null 처리를 따르지 않는다는 점이 재미있습니다. 그래서, 바이트 배열에 대해 문자열 변환을 해도 null을 포함해 문자열이 구성됩니다.

package main

import (
    "fmt"
)

func main() {

    buffer := []byte{61, 61, 0, 62, 62}
    t1 := string(buffer[:])

    fmt.Printf("%s\n", t1)
}

// 출력 결과: ==>>
// GoLand IDE의 콘솔 창으로 보면 "=="와 ">>" 사이에 '⍁' 문자가 '\0'을 대신해 출력합니다.

이런 경우, 만약 문자열을 null로 끊어내고 싶다면,

How can I convert a null-terminated string in a byte buffer to a string in Go?
; https://stackoverflow.com/questions/12359777/how-can-i-convert-a-null-terminated-string-in-a-byte-buffer-to-a-string-in-go

(문자열이 아닌) bytes 패키지의 Cut 함수를 사용해 말 그대로 null을 기준으로 미리 잘라내 문자열 변환을 해야 합니다.

t1, _, _ := bytes.Cut(buffer, []byte{0})




[이 글에 대해서 여러분들과 의견을 공유하고 싶습니다. 틀리거나 미흡한 부분 또는 의문 사항이 있으시면 언제든 댓글 남겨주십시오.]

[연관 글]






[최초 등록일: ]
[최종 수정일: 11/20/2024]

Creative Commons License
이 저작물은 크리에이티브 커먼즈 코리아 저작자표시-비영리-변경금지 2.0 대한민국 라이센스에 따라 이용하실 수 있습니다.
by SeongTae Jeong, mailto:techsharer at outlook.com

비밀번호

댓글 작성자
 




... 136  137  138  139  [140]  141  142  143  144  145  146  147  148  149  150  ...
NoWriterDateCnt.TitleFile(s)
1554정성태12/26/201335320Windows: 78. 마음에 드는 윈도우 8.1 태블릿 - 델 베뉴 8 프로 5830 [4]
1553정성태12/26/201322345개발 환경 구성: 206. JNBridgePro와 한글 인코딩 문제파일 다운로드1
1552정성태12/25/201327528개발 환경 구성: 205. JNBridgePro를 이용해 C#에서 Java메서드 호출 테스트파일 다운로드1
1551정성태12/24/201322678.NET Framework: 398. tech-days 미니 토요세미나 - 3회 C#편 PPT 자료파일 다운로드1
1550정성태12/13/201325063Windows: 77. Windows 8 - 잠시 사용을 안하는 경우 화면 잠김 상태로 빠지는 문제
1549정성태12/13/201328650VC++: 73. IIS - ISAPI 필터 제작하는 방법 [2]
1548정성태12/10/201321329오류 유형: 198. C# - 제네릭 covariance/contravariance 사용할 때 컴파일 오류가 발생한다면?
1547정성태12/10/201330893.NET Framework: 397. C# - OCX 컨트롤에 구현된 메서드에 배열을 in, out으로 전달하는 방법파일 다운로드2
1546정성태11/28/201324763.NET Framework: 396. C# - 프로퍼티로 정의하면 필드보다 느릴까요? - windbg / ollydbg [3]
1545정성태11/28/201328645.NET Framework: 395. C# - 프로퍼티로 정의하면 필드보다 느릴까요? [3]
1544정성태11/27/201325127개발 환경 구성: 204. Visual Studio Online "Monaco" 서비스와 github 연동
1543정성태11/27/201329877오류 유형: 197. error MSB8008: Specified platform toolset (v120) is not installed or invalid. [1]
1542정성태11/27/201335455오류 유형: 196. The procedure entry point InitializeCriticalSectionEx could not be located in the dynamic link library KERNEL32.dll
1541정성태11/22/201336655.NET Framework: 394. async/await 사용 시 hang 문제가 발생하는 경우 [7]파일 다운로드1
1540정성태11/20/201325106개발 환경 구성: 203. Azure - WEB SITES 서비스 소개 [4]
1539정성태11/19/201329107VS.NET IDE: 83. 형상 관리 서버 운영을 대신해 주는 Visual Studio 온라인 서비스
1538정성태11/19/201329981오류 유형: 195. 웹 사이트의 모든 정적 컨텐츠 요청에 대해 "Internal Server Error" 응답
1537정성태11/19/201321625오류 유형: 194. 윈도우 서버 백업으로 인해 Hyper-V VM들의 상태가 모두 "Backing up..." 상태로 오래 지속되는 문제
1536정성태11/19/201326442오류 유형: 193. 윈도우 서버 백업 - Hyper-V 가상 머신이 백업되지 않는 경우
1535정성태11/18/201326549.NET Framework: 393. Internet Explorer 11에서 ASP.NET 컨트롤의 크기가 달라지는 문제 [1]
1534정성태11/13/201326540.NET Framework: 392. .NET 스레드 콜 스택 덤프 (6) - MDbg를 이용한 방법 [2]파일 다운로드1
1533정성태11/12/201333755기타: 39. Internet Explorer 11에서 유튜브 동영상의 1080p 옵션이 보이지 않는 경우 [5]
1532정성태11/5/201334668Phone: 8. 안드로이드용 Xamarin 개발 시 겪을 만한 시행 착오 정리 [6]
1531정성태11/5/201326066VS.NET IDE: 82. Visual Studio에서 Attach 메서드를 이용해 디버깅을 시작한 경우 Breakpoint가 안 잡힌다면?
1530정성태11/5/201327445기타: 38. 오픈소스로 풀린 하드 디스크 관리 도구 - WindowSMART
1529정성태11/5/201323337오류 유형: 192. SQL 서버 - The transaction log for database '...' is full due to 'LOG_BACKUP'.
... 136  137  138  139  [140]  141  142  143  144  145  146  147  148  149  150  ...