1

I am trying to transform a UTF-8 string into a Latin-1 enabled string (converting all illegal Latin-1 chars into a '?') in order to save it into a txt file to be used in a Latin-1-only system.

For test purpose I used this code:

package main

import (
    "errors"
    "fmt"
    "os"

    "golang.org/x/text/encoding/charmap"
    "golang.org/x/text/transform"
)

func main() {
    strUTF8 := "example 1: Г, example 2: ≤, example 3: “, etc" // utf-8 string to be converted (not Latin-1 compatible, 3 uncompatibles runes)
    t := charmap.ISO8859_1.NewEncoder()                        // transformer to Latin-1

    ini := 0          // ini establishes the initial position of the string to be analized
    strISO88591 := "" // initiate Latin-1 compatible string
    counter := 0      // put a counter to forcibly break after 5 iters of the loop ('for' as a 'while' is not working as expected)

    err := errors.New("initiate err with non-nil value") // initiate err with non-nil value to enter the loop

    for err != nil { // loop should exit for when 'err != nil' evaluates to false, that is, when err == nil
        str, n, err := transform.String(t, strUTF8[ini:])
        if err != nil {
            ini = ini + n
            runes := []rune(strUTF8[ini:])
            ini = ini + len(string(runes[0])) //initial position of string in next iter should jump chars already converted + not allowed rune
            str = str + "?"
        }
        strISO88591 = strISO88591 + str

        // prints to display results
        fmt.Println("sISO88591:", strISO88591)
        fmt.Println("err:", err)
        fmt.Println("err!=nil:", err != nil)
        fmt.Println()

        // with the following 3 lines below it works (why not in the 'for' statement????)
        //if err == nil {
        //  break
        //}

        // put a counter to forcibly break after 5 iters of the loop
        counter += 1
        if counter > 4 {
            fmt.Println("breaking forcibly")
            break
        }

    }

    f, _ := os.Create("test.txt")
    defer f.Close()
    _, err = f.WriteString(strISO88591)
    if err != nil {
        panic(err)
    }

}

That code prints in the terminal:

sISO88591: example 1: ?
err: encoding: rune not supported by encoding.
err!=nil: true

sISO88591: example 1: ?, example 2: ?
err: encoding: rune not supported by encoding.
err!=nil: true

sISO88591: example 1: ?, example 2: ?, example 3: ?
err: encoding: rune not supported by encoding.
err!=nil: true

sISO88591: example 1: ?, example 2: ?, example 3: ?, etc     
err: <nil>
err!=nil: false

sISO88591: example 1: ?, example 2: ?, example 3: ?, etc, etc
err: <nil>
err!=nil: false

breaking forcibly

As we can see, after 4th iteration 'err!=nil' is evaluated to 'false' and so I expected it to exit the 'for err != nil' loop, but it never does (until I forcibly broke it with the help of a counter) . Isn´t 'for' supposed to work as other languages 'while'? Am I doing something wrong?

Specs: Go version: go1.19.5 windows/amd64

1 Answer 1

4

You are redeclaring err:

for err != nil {  // This is using err declared before
      str, n, err := transform.String(t, strUTF8[ini:]) // This is redeclaring and shadowing previous err
 ...

You can deal with it by:

for err != nil {
      var str string
      var n int
      str, n, err = transform.String(t, strUTF8[ini:]) // This is redeclaring and shadowing previous err
 ...

Sign up to request clarification or add additional context in comments.

3 Comments

Does it mean that the program considers the err variable beside the 'for' statement a diffrerent variable than the err variable inside the loop? Also, I always thought that a ':=' declaration could be applied selectively (in case of multiple return function ':=' worked both ways, ':=' for undeclared variables and, at the same time, '=' for declared variables)
Yes, they are different variables.
@MRodrigues, Loops in Go have two scopes: one starts at for and ends with the }, and another, nested, one starts at { and ends at }. Now let's cite the spec: «Unlike regular variable declarations, a short variable declaration may redeclare variables provided they were originally declared earlier in the same block (or the parameter lists if the block is the function body) with the same type, and at least one of the non-blank variables is new.» In your case, err is not in the same scope and hence is not _re_declared.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.