Golang – 用多个分隔符将字符串切割成切片或结构体

huangapple go评论86阅读模式
英文:

Golang - String with many delimiters to slice or struct

问题

我可以帮你将这段代码翻译成中文,但是请注意,我只会翻译代码部分,不会回答关于翻译的问题。以下是翻译的结果:

// 定义 Message 结构体
type Message struct {
    Key   string
    Value string
}

// 定义 Response 结构体
type Response struct {
    Connect  string
    Messages []Message
}

// 如果 220 Connected 存在
Response.Connect = "TRUE"

// 使用以下方式访问 220 Connected 和 end 之间的所有响应
Response.Messages[0].Key = "command"
Response.Messages[0].Value = "connect"

// 实现代码如下:
result, err := ioutil.ReadAll(conn)
data := strings.Split(string(result), "\n")

for i := range data {
    Reply := new(Response)
    if data[i] == "220 Connected." {
        Reply.Connect = "TRUE"
        Response.Messages = append(Response.Messages, Reply)
    }
}

希望对你有帮助!请记得仔细阅读代码并进行适当的调整。如果你对Golang还不熟悉,可以参考官方文档或其他资源来学习更多。

英文:

I have the following string returned as response from a TCP connection :

220 Connected.\ncommand:connect\nemail:ERROR_MAIL_MISSING\nstatus:CMD_ERROR\nend

I want actually to transform this response to the following golang struct :

type Message struct {
    Key string
    Value string
}

type Response struct {
    Connect string
    Messages []Message
}

If 220 Connected is always present means :

Response.Connect => TRUE

All response between 220 Connected. and end can be accessed using :

Response[0].Key => "command"
Response[0].Value => "connect"

This is what I actually achieved :

result, err := ioutil.ReadAll(conn)
        data := strings.Split(string(result), "\n")

        for i := range data {
                Reply := new(Response)
                if data[i] == "220 Connected." {
                        Reply.Connect = "TRUE"
                        Response = append(Response, Reply)
                }
        }

Any hint how this can be achieved ? I'm a newbie with Golang

答案1

得分: 3

你需要做更多的工作来提取你想要的数据。这是一个示例程序,可以正确填充Messages数组。我将在下面的注释中说明我是如何从你的尝试中进行修改的。

package main

import "fmt"
import "strings"


type Message struct {
    Key string
    Value string
}

type Response struct {
    Connect string
    Messages []Message
}

func main() {
    result := `220 Connected.\ncommand:connect\nemail:ERROR_MAIL_MISSING\nstatus:CMD_ERROR\nend`
    data := strings.Split(string(result), "\\n")

    r := &Response{}
    for i := range data {
        if data[i] == "220 Connected." {
            r.Connect = "TRUE"
        } else {
            tokens := strings.Split(data[i], ":")
            if len(tokens) == 2 {
                m := Message{tokens[0], tokens[1]}
                r.Messages = append(r.Messages, m)
            }
        }
    }
    for i := range r.Messages {
        fmt.Println(r.Messages[i])
    }
}

在你的尝试中,for循环的代码如下:

for i := range data {
    Reply := new(Response)
    if data[i] == "220 Connected." {
        Reply.Connect = "TRUE"
        Response = append(Response, Reply)
    }
}

这与你的类型和数据布局不一致。在每次迭代中,你创建了一个新的Response实例,实际上你只需要一个。在每次迭代中,你需要一个新的Message实例。这会导致一些问题,首先你查看的数据不是一个响应,而是一条消息;其次,你不断地覆盖先前的消息(该对象仅在循环范围内)。为了纠正这个问题,我们在循环之前实例化Response对象。其次,你需要进行第二次拆分以获取你的数据。因此,在循环内部,我们使用冒号进行拆分,以分离每条消息的键和值。然后我在添加之前进行了一个快速的长度检查(第一次运行时我遇到了一个恐慌,第一个if可能失败了,这意味着你需要对其进行一些编辑)。如果你没有得到连接的220,你应该将该值设置为false。你应该在最后一个else中进行消息拆分,但仅仅不是220 Connected.是不足以假设当前项是Message的,这就是为什么我添加了边界检查的原因。请注意,在这个循环内部,我为每个键值对实例化了一个新的消息。我们使用append将其添加到Messages数组中,而不是将Response追加到彼此上(这永远不会起作用,因为它是一个结构体,而不是切片或映射)。这也使得Message持久存在,而不是每次到达循环底部时都超出范围(m将超出范围,但在r.Messages中的实例仍然存在)。

希望对你有所帮助!

英文:

You need to do a bit more work to extract the data you want. Here's a sample program that correctly populates the Messages array. I'll update with some notes on what's I did to move from your attempt to what you're looking for.

package main

import "fmt"
import "strings"


type Message struct {
    Key string
    Value string
}

type Response struct {
    Connect string
    Messages []Message
}
func main() {
	result := `220 Connected.\ncommand:connect\nemail:ERROR_MAIL_MISSING\nstatus:CMD_ERROR\nend`
        data := strings.Split(string(result), "\\")
	
	r := &Response{}
        for i := range data {
                if data[i] == "220 Connected." {
                        r.Connect = "TRUE"
                } else {
		    tokens := strings.Split(data[i], ":")
		    if len(tokens) == 2 {
		    	m := Message{tokens[0], tokens[1]}
		    	r.Messages = append(r.Messages, m)
		    }
		}
        }
        for i := range r.Messages {
             fmt.Println(r.Messages[i])
        }
}

https://play.golang.org/p/Hs8aqYPyuM

Alright, so first lets list some problems. In your attempt the for loop looks like this;

  for i := range data {
            Reply := new(Response)
            if data[i] == "220 Connected." {
                    Reply.Connect = "TRUE"
                    Response = append(Response, Reply)
            }
    }

This isn't consistent with your types/data layout. On every iteration you create a new Response instance, you actually only need one. What you want on each iteration is a new Message instance. This causes a few problems, firstly the data you're looking at isn't a response, it's a message, secondly you keep overwriting the previous one (that object is only scoped for the loop). To correct this we instantiate the Response object before the loop. Secondly, you need a second split in order to get your data out. So inside the loop we split on a colon to separate the key and value of each message. Then I have a quick check on the length before adding it (I got a panic on first run, the first if probably failed, meaning you need to edit that a bit. If you don't get 220 for connected you want to set that value to false, you should do the message split an a final else but simply not being 220 Connected. isn't sufficient to assume the current item is a Message which is why I added bounds check). Note that inside this loop I instantiate a new message for each key value pair. We use append there to append to the Messages array, not appending Response's onto eachother (that will never work since it's a struct, not a slice or map). This also makes it so the Message persists rather than going out of scope each time we hit the bottom of the loop (m will go out of scope but the instance in r.Messages will still be around).

huangapple
  • 本文由 发表于 2015年12月1日 01:46:45
  • 转载请务必保留本文链接:https://go.coder-hub.com/34004764.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定