2017-04-25 81 views
1

我原BUF格式是这样的:如何将带有可变结构的消息拼合成protobuf?

package main; 

message Test { 
    optional string id = 1; 
    optional string name = 2; 
    optional string age = 3; 
} 

然后我使用下面的代码在golang输入填充protobuf的文件。 str已经被解析。

test = &Test{ 
    id: proto.String(str[0]), 
    name: proto.String(str[1]), 
    age: proto.String(str[2]), 
}, 

一个条件我要处理的是,在测试结构的一个或多个可选字段可能是不存在的随机,我不知道在前进。我如何在golang中处理?

给予更多的情况下,真实数据可以像这些文件中:

id=1, name=peter, age=24 
id=2, age=30 
name=mary, age=31 
id=100 
name=bob 
age=11 
+0

你不能简单地检查'if arg [n] ==“”'? – RayfenWindspear

+0

编号任何字段可以消失,我不知道哪一个丢失,如果我只是检查长度 – drdot

+0

你是否解析命令行参数?如果是这样,请使用https://godoc.org/flag软件包。否则,我们需要在这些参数来自于更多的背景下。 – RayfenWindspear

回答

1

你可以使用正则表达式来改变你的输入字符串转换为有效的JSON,使用encoding/json包解析它。这具有让分析器为您处理所有事情的优势。这是你的特定情况下的正则表达式。

基本上,正则表达式寻找field=value并替换为"field" : "value"并将其包装在{}中以创建有效的JSON。逗号保持原样。

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

package main 

import (
    "encoding/json" 
    "errors" 
    "fmt" 
    "log" 
    "regexp" 
) 

var ins = []string{ 
    `id=1, name=peter, age=24`, 
    `id=2, age=30`, 
    `name=mary, age=31`, 
    `id=100`, 
    `name=bob`, 
    `age=11`, 
} 

var ParseError = errors.New("bad parser input") 
var Regex *regexp.Regexp 

type Test struct { 
    ID string 
    Name string 
    Age string 
} 

func (t *Test) String() string { 
    return fmt.Sprintf("ID: %s, Name: %s, Age: %s", t.ID, t.Name, t.Age) 
} 

func main() { 
    var err error 
    Regex, err = regexp.Compile(`([^,\s]*)=([^,\s]*)`) 
    if err != nil { 
     log.Panic(err) 
    } 
    for _, v := range ins { 

     test, err := ParseLine(v) 
     if err != nil { 
      log.Panic(err) 
     } 
     fmt.Println(test) 
    } 
} 

func ParseLine(inp string) (*Test, error) { 
    JSON := fmt.Sprintf("{%s}", Regex.ReplaceAllString(inp, `"$1" : "$2"`)) 
    test := &Test{} 
    err := json.Unmarshal([]byte(JSON), test) 
    if err != nil { 
     return nil, err 
    } 
    return test, nil 
} 

以下是我认为是你所追求的最低工作的情况下,虽然我没有与协议缓冲区不够熟悉而获得的字符串打印权...甚至验证它们是否正确。请注意,这不会在操场上运行。

package main 

import (
    "errors" 
    "fmt" 
    "log" 
    "regexp" 
    "github.com/golang/protobuf/jsonpb" 
    _ "github.com/golang/protobuf/proto" 
) 

var ins = []string{ 
    `id=1, name=peter, age=24`, 
    `id=2, age=30`, 
    `name=mary, age=31`, 
    `id=100`, 
    `name=bob`, 
    `age=11`, 
} 

var ParseError = errors.New("bad parser input") 
var Regex *regexp.Regexp 

type Test struct { 
    ID *string `protobuf:"bytes,1,opt,name=id,json=id" json:"id,omitempty"` 
    Name *string `protobuf:"bytes,2,opt,name=name,json=name" json:"name,omitempty"` 
    Age *string `protobuf:"bytes,3,opt,name=age,json=age" json:"age,omitempty"` 
} 

func (t *Test) Reset() { 
    *t = Test{} 
} 


func (*Test) ProtoMessage() {} 
func (*Test) Descriptor() ([]byte, []int) {return []byte{}, []int{0}} 

func (t *Test) String() string { 
    return fmt.Sprintf("ID: %v, Name: %v, Age: %v", t.ID, t.Name, t.Age) 
} 

func main() { 
    var err error 
    Regex, err = regexp.Compile(`([^,\s]*)=([^,\s]*)`) 
    if err != nil { 
     log.Panic(err) 
    } 
    for _, v := range ins { 

     test, err := ParseLine(v) 
     if err != nil { 
      fmt.Println(err) 
      log.Panic(err) 
     } 
     fmt.Println(test) 
    } 
} 

func ParseLine(inp string) (*Test, error) { 
    JSON := fmt.Sprintf("{%s}", Regex.ReplaceAllString(inp, `"$1" : "$2"`)) 
    test := &Test{} 
    err := jsonpb.UnmarshalString(JSON, test) 
    if err != nil { 
     return nil, err 
    } 
    return test, nil 
} 
+0

解析很不错。但我的主要问题是如何将其序列化为protobuf?即,如果我们看到protobuf中缺少一些字段,请不要填充它。 – drdot

+0

啊,是的,让我说说。我想我会尽可能通用 – RayfenWindspear

+0

看起来有一个特定于协议缓冲区的json包。 https://godoc.org/github.com/golang/protobuf/jsonpb。无可否认,我自己并没有真正使用过协议缓冲区,所以我不确定我能为此提供多大帮助。另外,该软件包不是标准软件包,所以它不能在操场上运行。看看并告诉我它是否足够简单。 – RayfenWindspear

0

看起来你可以写你的输入类似下面的每一行解析器。

注意:我没有使用proto值的结构,因为作为外部软件包,它不能在游乐场中导入。

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

package main 

import (
    "errors" 
    "fmt" 
    "strings" 
) 

var ins = []string{ 
    `id=1, name=peter, age=24`, 
    `id=2, age=30`, 
    `name=mary, age=31`, 
    `id=100`, 
    `name=bob`, 
    `age=11`, 
} 

var ParseError = errors.New("bad parser input") 

type Test struct { 
    ID string 
    Name string 
    Age string 
} 

func (t *Test) String() string { 
    return fmt.Sprintf("ID: %s, Name: %s, Age: %s", t.ID, t.Name, t.Age) 
} 

func main() { 
    for _, v := range ins { 
     t, err := ParseLine(v) 
     if err != nil { 
      fmt.Println(err) 
     } else { 
      fmt.Println(t) 
     } 
    } 
} 

func ParseLine(inp string) (*Test, error) { 
    splt := strings.Split(inp, ",") 
    test := &Test{} 
    for _, f := range splt { 
     fieldVal := strings.Split(strings.TrimSpace(f), "=") 
     switch strings.TrimSpace(fieldVal[0]) { 
     case "id": 
      test.ID = strings.TrimSpace(fieldVal[1]) 
     case "name": 
      test.Name = strings.TrimSpace(fieldVal[1]) 
     case "age": 
      test.Age = strings.TrimSpace(fieldVal[1]) 
     default: 
      return nil, ParseError 
     } 
    } 
    return test, nil 
} 
+0

刚刚让它更便携。 – RayfenWindspear

+0

感谢您的解决方案。但是,可选字段的数量可能很大,我希望为每个字段避免这么多的开关情况。有没有办法绕过结构? – drdot

+0

我想过一张地图。但是,我想有一个有序的结构。 – drdot