将文本文件解析以匹配字符串并提取值(使用Golang)

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

Parsing of text file to match string and extract value (in Golang)

问题

我正在思考一个似乎可能很常见但在网上找不到任何示例的需求。

我有一个像这样的文件:

  1. answer VNET_1_DHCP yes
  2. answer VNET_1_DHCP_CFG_HASH 4CF2C196E368CE83B9D1895C5E05301CDFDEBCA0
  3. answer VNET_1_HOSTONLY_NETMASK 255.255.255.0
  4. answer VNET_1_HOSTONLY_SUBNET 192.168.224.0
  5. answer VNET_1_VIRTUAL_ADAPTER yes
  6. answer VNET_8_DHCP yes
  7. answer VNET_8_DHCP_CFG_HASH D326C0BC7FF6C38C57AF341F9075E576C175B250
  8. answer VNET_8_HOSTONLY_NETMASK 255.255.255.0
  9. answer VNET_8_HOSTONLY_SUBNET 172.16.102.0
  10. answer VNET_8_NAT yes
  11. answer VNET_8_VIRTUAL_ADAPTER yes

我需要提取特定子网(192.168.224.0)的VNET编号。VNET编号可能会变化(理论上,子网甚至可能不存在)。因此,我需要匹配子网是否存在,如果存在,则提取网络编号(在此示例中为1)。

我发现在BASH中实现这个非常简单:

  1. if grep -q 192.168.224.0 ./networking; then
  2. echo "The ${VMNET_SUBNET} network already exists"
  3. NETWORK_NUMBER=$(grep ${VMNET_SUBNET} ./networking | cut -d'_' -f 2)
  4. echo NETWORK_NUMBER
  5. else <执行创建操作.....>

我正在尝试找到使用Go实现这个的最简单方法。

谢谢。

英文:

I am scratching my head around a need that seems to be potentially common but I couldn't locate any example on the web.

I have a file like this:

  1. answer VNET_1_DHCP yes
  2. answer VNET_1_DHCP_CFG_HASH 4CF2C196E368CE83B9D1895C5E05301CDFDEBCA0
  3. answer VNET_1_HOSTONLY_NETMASK 255.255.255.0
  4. answer VNET_1_HOSTONLY_SUBNET 192.168.224.0
  5. answer VNET_1_VIRTUAL_ADAPTER yes
  6. answer VNET_8_DHCP yes
  7. answer VNET_8_DHCP_CFG_HASH D326C0BC7FF6C38C57AF341F9075E576C175B250
  8. answer VNET_8_HOSTONLY_NETMASK 255.255.255.0
  9. answer VNET_8_HOSTONLY_SUBNET 172.16.102.0
  10. answer VNET_8_NAT yes
  11. answer VNET_8_VIRTUAL_ADAPTER yes

I need to extract the VNET number of a specific subnet (192.168.224.0). VNET numbers could vary (and the subnet could, in theory, not even exist). So I need to match if the subnet exists, and if exists extract the network number (1 in this example).

I found it to be SUPER easy to implement this in BASH:

  1. if grep -q 192.168.224.0 ./networking; then
  2. echo &quot;The ${VMNET_SUBNET} network already exists&quot;
  3. NETWORK_NUMBER=$(grep ${VMNET_SUBNET} ./networking | cut -d&#39;_&#39; -f 2)
  4. echo NETWORK_NUMBER
  5. else &lt;do something to create it.....&gt;

I am trying to find the easiest way to implement this using Go.

Thanks.

答案1

得分: 10

你可以使用正则表达式(regular expression)来实现:

  1. re := regexp.MustCompile(`.*VNET_(\d+)_.*192.168.224.0`)
  2. matches := re.FindStringSubmatch(text)
  3. fmt.Println(matches[1])

Playground: http://play.golang.org/p/NQlA2BObtU.

英文:

You can use a regular expression:

  1. re := regexp.MustCompile(`.*VNET_(\d+)_.*192.168.224.0`)
  2. matches := re.FindStringSubmatch(text)
  3. fmt.Println(matches[1])

Playground: http://play.golang.org/p/NQlA2BObtU.

答案2

得分: 5

这是一种基于 @ainar-g 的答案的稳健的解析数据的方法:

http://play.golang.org/p/6-PELcLvVz

这里的目标是使用以下类型将每个VNET的属性存储在一个映射中:

  1. type vnet map[int]map[string]string

这段代码:

  1. var re = regexp.MustCompile(`.*VNET_(\d+)_([^\s]+) (.*)`)
  2. func ReadVnet(r io.Reader) vnet {
  3. s := bufio.NewScanner(r)
  4. v := make(vnet)
  5. for s.Scan() {
  6. matches := re.FindStringSubmatch(s.Text())
  7. id, err := strconv.Atoi(matches[1])
  8. if err != nil {
  9. continue
  10. }
  11. if _, ok := v[id]; !ok {
  12. v[id] = make(map[string]string)
  13. }
  14. v[id][matches[2]] = matches[3]
  15. }
  16. return v
  17. }

创建了所需的映射:

  1. map[1:map[DHCP:yes DHCP_CFG_HASH:4CF2C196E368CE83B9D1895C5E05301CDFDEBCA0 HOSTONLY_NETMASK:255.255.255.0 HOSTONLY_SUBNET:192.168.224.0 VIRTUAL_ADAPTER:yes] 8:map[DHCP:yes DHCP_CFG_HASH:D326C0BC7FF6C38C57AF341F9075E576C175B250 HOSTONLY_NETMASK:255.255.255.0 HOSTONLY_SUBNET:172.16.102.0 NAT:yes VIRTUAL_ADAPTER:yes]]

现在,您可以迭代映射以找到感兴趣的项:

  1. func main() {
  2. v := ReadVnet(bytes.NewBufferString(text))
  3. for id, properties := range v {
  4. if ip, ok := properties["HOSTONLY_SUBNET"]; ok && ip == "192.168.224.0" {
  5. fmt.Println(id)
  6. return
  7. }
  8. }
  9. }
英文:

Here is a robust way to parse these data that builds on @ainar-g's answer:

http://play.golang.org/p/6-PELcLvVz

The goal here is to store the properties for each VNET in a map, using the following type:

  1. type vnet map[int]map[string]string

This code:

  1. var re = regexp.MustCompile(`.*VNET_(\d+)_([^\s]+) (.*)`)
  2. func ReadVnet(r io.Reader) vnet {
  3. s := bufio.NewScanner(r)
  4. v := make(vnet)
  5. for s.Scan() {
  6. matches := re.FindStringSubmatch(s.Text())
  7. id, err := strconv.Atoi(matches[1])
  8. if err != nil {
  9. continue
  10. }
  11. if _, ok := v[id]; !ok {
  12. v[id] = make(map[string]string)
  13. }
  14. v[id][matches[2]] = matches[3]
  15. }
  16. return v
  17. }

creates the map in question:

  1. map[1:map[DHCP:yes DHCP_CFG_HASH:4CF2C196E368CE83B9D1895C5E05301CDFDEBCA0 HOSTONLY_NETMASK:255.255.255.0 HOSTONLY_SUBNET:192.168.224.0 VIRTUAL_ADAPTER:yes] 8:map[DHCP:yes DHCP_CFG_HASH:D326C0BC7FF6C38C57AF341F9075E576C175B250 HOSTONLY_NETMASK:255.255.255.0 HOSTONLY_SUBNET:172.16.102.0 NAT:yes VIRTUAL_ADAPTER:yes]]

Now you can iterate on the map to find the item of interest:

  1. func main() {
  2. v := ReadVnet(bytes.NewBufferString(text))
  3. for id, properties := range v {
  4. if ip, ok := properties[&quot;HOSTONLY_SUBNET&quot;]; ok &amp;&amp; ip == &quot;192.168.224.0&quot; {
  5. fmt.Println(id)
  6. return
  7. }
  8. }
  9. }

答案3

得分: 3

这是一个没有正则表达式的版本:

  1. idxEnd := strings.Index(txt, "192.168.224.0")
  2. idxVNET := strings.LastIndex(txt[:idxEnd], "VNET_")
  3. beginNumber := idxVNET + 5
  4. length := strings.Index(txt[beginNumber:idxEnd], "_")
  5. number, _ := strconv.Atoi(txt[beginNumber : beginNumber+length])
  6. fmt.Printf("number: %T %v\n", number, number)

如果你尝试在一个非常(非常)大的字符串上执行这个操作,它应该会更快。

英文:

This is a version without regexp:

  1. idxEnd := strings.Index(txt, &quot;192.168.224.0&quot;)
  2. idxVNET := strings.LastIndex(txt[:idxEnd], &quot;VNET_&quot;)
  3. beginNumber := idxVNET + 5
  4. length := strings.Index(txt[beginNumber:idxEnd], &quot;_&quot;)
  5. number, _ := strconv.Atoi(txt[beginNumber : beginNumber+length])
  6. fmt.Printf(&quot;number: %T %v\n&quot;, number, number)

Would you try to do that on a very (very) big string, it should be faster.

huangapple
  • 本文由 发表于 2015年12月24日 00:49:27
  • 转载请务必保留本文链接:https://go.coder-hub.com/34440268.html
匿名

发表评论

匿名网友

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

确定