// +build ignore,OMIT package main import ( "encoding/json" "fmt" "log" "strings" ) type romanNumeral int var numerals = []struct { s string v int }{ {"M", 1000}, {"CM", 900}, {"D", 500}, {"CD", 400}, {"C", 100}, {"XC", 90}, {"L", 50}, {"XL", 40}, {"X", 10}, {"IX", 9}, {"V", 5}, {"IV", 4}, {"I", 1}, } func (n romanNumeral) String() string { res := "" v := int(n) for _, num := range numerals { res += strings.Repeat(num.s, v/num.v) v %= num.v } return res } func parseRomanNumeral(s string) (romanNumeral, error) { res := 0 for _, num := range numerals { for strings.HasPrefix(s, num.s) { res += num.v s = s[len(num.s):] } } return romanNumeral(res), nil } func (n romanNumeral) MarshalJSON() ([]byte, error) { if n <= 0 { return nil, fmt.Errorf("Romans had only natural (=>1) numbers") } return json.Marshal(n.String()) } func (n *romanNumeral) UnmarshalJSON(data []byte) error { var s string if err := json.Unmarshal(data, &s); err != nil { return err } p, err := parseRomanNumeral(s) if err == nil { *n = p } return err } type Movie struct { Title string Year romanNumeral } func main() { // Encoding movies := []Movie{{"E.T.", 1982}, {"The Matrix", 1999}, {"Casablanca", 1942}} res, err := json.MarshalIndent(movies, "", "\t") // HL if err != nil { log.Fatal(err) } fmt.Printf("Movies: %s\n", res) // Decoding var m Movie inputText := `{"Title": "Alien", "Year":"MCMLXXIX"}` if err := json.NewDecoder(strings.NewReader(inputText)).Decode(&m); err != nil { log.Fatal(err) } fmt.Printf("%s was released in %d\n", m.Title, m.Year) }