英文:
Using Go 'for' loop as 'while'
问题
我正在尝试将一个UTF-8字符串转换为Latin-1编码的字符串(将所有非法的Latin-1字符转换为'?'),以便将其保存到一个只支持Latin-1的系统中的txt文件中。
为了测试目的,我使用了以下代码:
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字符串(不兼容Latin-1,有3个不兼容的符文)
t := charmap.ISO8859_1.NewEncoder() // 转换器,用于转换为Latin-1
ini := 0 // ini用于指定要分析的字符串的初始位置
strISO88591 := "" // 初始化兼容Latin-1的字符串
counter := 0 // 设置一个计数器,在循环的前5次迭代后强制退出('for'作为'while'使用时不按预期工作)
err := errors.New("initiate err with non-nil value") // 将err初始化为非nil值,以便进入循环
for err != nil { // 当'err != nil'为false时,循环应该退出,即当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])) // 下一次迭代中字符串的初始位置应跳过已转换的字符和不允许的符文
str = str + "?"
}
strISO88591 = strISO88591 + str
// 打印结果
fmt.Println("sISO88591:", strISO88591)
fmt.Println("err:", err)
fmt.Println("err!=nil:", err != nil)
fmt.Println()
// 使用以下3行代码可以正常工作(为什么在'for'语句中不行???)
//if err == nil {
// break
//}
// 设置一个计数器,在循环的前5次迭代后强制退出
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)
}
}
该代码在终端中打印出以下内容:
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
正如我们所看到的,第4次迭代后,'err!=nil'被评估为'false',所以我期望它退出'for err != nil'循环,但它从未这样做(直到我使用计数器强制中断)。
'for'不应该像其他语言的'while'一样工作吗?我做错了什么吗?
规格:
Go版本:go1.19.5 windows/amd64
英文:
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
得分: 4
你正在重新声明 err
:
for err != nil { // 这里使用了之前声明的 err
str, n, err := transform.String(t, strUTF8[ini:]) // 这里重新声明并遮蔽了之前的 err
...
你可以通过以下方式解决这个问题:
for err != nil {
var str string
var n int
str, n, err = transform.String(t, strUTF8[ini:]) // 这里重新声明并遮蔽了之前的 err
...
英文:
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
...
</details>
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论