github.com/graybobo/golang.org-package-offline-cache@v0.0.0-20200626051047-6608995c132f/x/talks/2015/json/roman_numerals.go (about)

     1  // +build OMIT
     2  
     3  package main
     4  
     5  import (
     6  	"encoding/json"
     7  	"fmt"
     8  	"log"
     9  	"strings"
    10  )
    11  
    12  type romanNumeral int
    13  
    14  var numerals = []struct {
    15  	s string
    16  	v int
    17  }{
    18  	{"M", 1000}, {"CM", 900},
    19  	{"D", 500}, {"CD", 400},
    20  	{"C", 100}, {"XC", 90},
    21  	{"L", 50}, {"XL", 40},
    22  	{"X", 10}, {"IX", 9},
    23  	{"V", 5}, {"IV", 4},
    24  	{"I", 1},
    25  }
    26  
    27  func (n romanNumeral) String() string {
    28  	res := ""
    29  	v := int(n)
    30  	for _, num := range numerals {
    31  		res += strings.Repeat(num.s, v/num.v)
    32  		v %= num.v
    33  	}
    34  	return res
    35  }
    36  
    37  func parseRomanNumeral(s string) (romanNumeral, error) {
    38  	res := 0
    39  	for _, num := range numerals {
    40  		for strings.HasPrefix(s, num.s) {
    41  			res += num.v
    42  			s = s[len(num.s):]
    43  		}
    44  	}
    45  	return romanNumeral(res), nil
    46  }
    47  
    48  func (n romanNumeral) MarshalJSON() ([]byte, error) {
    49  	if n <= 0 {
    50  		return nil, fmt.Errorf("Romans had only natural (=>1) numbers")
    51  	}
    52  	return json.Marshal(n.String())
    53  }
    54  
    55  func (n *romanNumeral) UnmarshalJSON(data []byte) error {
    56  	var s string
    57  	if err := json.Unmarshal(data, &s); err != nil {
    58  		return err
    59  	}
    60  	p, err := parseRomanNumeral(s)
    61  	if err == nil {
    62  		*n = p
    63  	}
    64  	return err
    65  }
    66  
    67  type Movie struct {
    68  	Title string
    69  	Year  romanNumeral
    70  }
    71  
    72  func main() {
    73  	// Encoding
    74  	movies := []Movie{{"E.T.", 1982}, {"The Matrix", 1999}, {"Casablanca", 1942}}
    75  	res, err := json.MarshalIndent(movies, "", "\t") // HL
    76  	if err != nil {
    77  		log.Fatal(err)
    78  	}
    79  	fmt.Printf("Movies: %s\n", res)
    80  
    81  	// Decoding
    82  	var m Movie
    83  	inputText := `{"Title": "Alien", "Year":"MCMLXXIX"}`
    84  	if err := json.NewDecoder(strings.NewReader(inputText)).Decode(&m); err != nil {
    85  		log.Fatal(err)
    86  	}
    87  	fmt.Printf("%s was released in %d\n", m.Title, m.Year)
    88  }