github.com/enetx/g@v1.0.80/string_encdec.go (about) 1 package g 2 3 import ( 4 "encoding/base64" 5 "encoding/hex" 6 "encoding/json" 7 "encoding/xml" 8 "html" 9 "net/url" 10 "strconv" 11 ) 12 13 type ( 14 // A struct that wraps an String for encoding. 15 enc struct{ str String } 16 17 // A struct that wraps an String for decoding. 18 dec struct{ str String } 19 ) 20 21 // Enc returns an enc struct wrapping the given String. 22 func (s String) Enc() enc { return enc{s} } 23 24 // Dec returns a dec struct wrapping the given String. 25 func (s String) Dec() dec { return dec{s} } 26 27 // Base64 encodes the wrapped String using Base64 and returns the encoded result as an String. 28 func (e enc) Base64() String { return String(base64.StdEncoding.EncodeToString(e.str.ToBytes())) } 29 30 // Base64 decodes the wrapped String using Base64 and returns the decoded result as an String. 31 func (d dec) Base64() Result[String] { 32 decoded, err := base64.StdEncoding.DecodeString(d.str.Std()) 33 if err != nil { 34 return Err[String](err) 35 } 36 37 return Ok(String(decoded)) 38 } 39 40 // JSON encodes the provided data as JSON and returns the result as an String. 41 func (enc) JSON(data any) Result[String] { 42 jsonData, err := json.Marshal(data) 43 if err != nil { 44 return Err[String](err) 45 } 46 47 return Ok(String(jsonData)) 48 } 49 50 // JSON decodes the wrapped String using JSON and unmarshals it into the provided data object. 51 func (d dec) JSON(data any) Result[String] { 52 err := json.Unmarshal(d.str.ToBytes(), data) 53 if err != nil { 54 return Err[String](err) 55 } 56 57 return Ok(d.str) 58 } 59 60 // XML encodes the provided data as XML and returns the result as an String. 61 // The optional prefix and indent String values can be provided for XML indentation. 62 func (enc) XML(data any, s ...String) Result[String] { 63 var ( 64 prefix string 65 indent string 66 ) 67 68 if len(s) > 1 { 69 prefix = s[0].Std() 70 indent = s[1].Std() 71 } 72 73 xmlData, err := xml.MarshalIndent(data, prefix, indent) 74 if err != nil { 75 return Err[String](err) 76 } 77 78 return Ok(String(xmlData)) 79 } 80 81 // XML decodes the wrapped String using XML and unmarshals it into the provided data object. 82 func (d dec) XML(data any) Result[String] { 83 err := xml.Unmarshal(d.str.ToBytes(), data) 84 if err != nil { 85 return Err[String](err) 86 } 87 88 return Ok(d.str) 89 } 90 91 // URL encodes the input string, escaping reserved characters as per RFC 2396. 92 // If safe characters are provided, they will not be encoded. 93 // 94 // Parameters: 95 // 96 // - safe (String): Optional. Characters to exclude from encoding. 97 // If provided, the function will not encode these characters. 98 // 99 // Returns: 100 // 101 // - String: Encoded URL string. 102 func (e enc) URL(safe ...String) String { 103 reserved := String(";/?:@&=+$,") // Reserved characters as per RFC 2396 104 if len(safe) != 0 { 105 reserved = safe[0] 106 } 107 108 enc := NewBuilder() 109 110 for _, r := range e.str { 111 if reserved.ContainsRune(r) { 112 enc.WriteRune(r) 113 continue 114 } 115 116 enc.Write(String(url.QueryEscape(string(r)))) 117 } 118 119 return enc.String() 120 } 121 122 // URL URL-decodes the wrapped String and returns the decoded result as an String. 123 func (d dec) URL() Result[String] { 124 result, err := url.QueryUnescape(d.str.Std()) 125 if err != nil { 126 return Err[String](err) 127 } 128 129 return Ok(String(result)) 130 } 131 132 // HTML HTML-encodes the wrapped String and returns the encoded result as an String. 133 func (e enc) HTML() String { return String(html.EscapeString(e.str.Std())) } 134 135 // HTML HTML-decodes the wrapped String and returns the decoded result as an String. 136 func (d dec) HTML() String { return String(html.UnescapeString(d.str.Std())) } 137 138 // Rot13 encodes the wrapped String using ROT13 cipher and returns the encoded result as an 139 // String. 140 func (e enc) Rot13() String { 141 rot := func(r rune) rune { 142 switch { 143 case r >= 'A' && r <= 'Z': 144 return 'A' + (r-'A'+13)%26 145 case r >= 'a' && r <= 'z': 146 return 'a' + (r-'a'+13)%26 147 default: 148 return r 149 } 150 } 151 152 return e.str.Map(rot) 153 } 154 155 // Rot13 decodes the wrapped String using ROT13 cipher and returns the decoded result as an 156 // String. 157 func (d dec) Rot13() String { return d.str.Enc().Rot13() } 158 159 // XOR encodes the wrapped String using XOR cipher with the given key and returns the encoded 160 // result as an String. 161 func (e enc) XOR(key String) String { 162 if key.Empty() { 163 return e.str 164 } 165 166 encrypted := e.str.ToBytes() 167 168 for i := range len(e.str) { 169 encrypted[i] ^= key[i%len(key)] 170 } 171 172 return String(encrypted) 173 } 174 175 // XOR decodes the wrapped String using XOR cipher with the given key and returns the decoded 176 // result as an String. 177 func (d dec) XOR(key String) String { return d.str.Enc().XOR(key) } 178 179 // Hex hex-encodes the wrapped String and returns the encoded result as an String. 180 func (e enc) Hex() String { 181 result := NewBuilder() 182 for i := range len(e.str) { 183 result.Write(Int(e.str[i]).ToHex()) 184 } 185 186 return result.String() 187 } 188 189 // Hex hex-decodes the wrapped String and returns the decoded result as an String. 190 func (d dec) Hex() Result[String] { 191 result, err := hex.DecodeString(d.str.Std()) 192 if err != nil { 193 return Err[String](err) 194 } 195 196 return Ok(String(result)) 197 } 198 199 // Octal returns the octal representation of the encoded string. 200 func (e enc) Octal() String { 201 result := NewSlice[String](e.str.LenRunes()) 202 for i, char := range e.str.ToRunes() { 203 result.Set(Int(i), Int(char).ToOctal()) 204 } 205 206 return result.Join(" ") 207 } 208 209 // Octal returns the octal representation of the decimal-encoded string. 210 func (d dec) Octal() Result[String] { 211 result := NewBuilder() 212 213 for _, v := range d.str.Split(" ").Collect() { 214 n, err := strconv.ParseUint(v.Std(), 8, 32) 215 if err != nil { 216 return Err[String](err) 217 } 218 219 result.WriteRune(rune(n)) 220 } 221 222 return Ok(result.String()) 223 } 224 225 // Binary converts the wrapped String to its binary representation as an String. 226 func (e enc) Binary() String { 227 result := NewBuilder() 228 for i := range len(e.str) { 229 result.Write(Int(e.str[i]).ToBinary()) 230 } 231 232 return result.String() 233 } 234 235 // Binary converts the wrapped binary String back to its original String representation. 236 func (d dec) Binary() Result[String] { 237 var result Bytes 238 239 for i := 0; i+8 <= len(d.str); i += 8 { 240 b, err := strconv.ParseUint(d.str[i:i+8].Std(), 2, 8) 241 if err != nil { 242 return Err[String](err) 243 } 244 245 result = append(result, byte(b)) 246 } 247 248 return Ok(result.ToString()) 249 }