|
1 | | -# StringFormatter |
2 | | - |
3 | | -* A set of a ***high performance string tools*** that helps to build strings from templates and process text faster than with `fmt`!!!. |
4 | | -* Allows to **format code in appropriate style** (`Snake`, `Kebab`, `Camel`) and case. |
5 | | -* Slice printing is **50% faster with 8 items** slice and **250% with 20 items** slice |
6 | | - |
| 1 | +# Wissance/StringFormatter |
7 | 2 |  |
8 | 3 |  |
9 | 4 |  |
10 | 5 |  |
11 | | - |
| 6 | +[](https://github.com/Wissance/stringFormatter/actions/workflows/ci.yml) |
12 | 7 |
|
13 | | - |
| 8 | + |
14 | 9 |
|
15 | | -## 1. Features |
| 10 | +`StringFormatter` is a ***high-performance*** Go library for string (text) formatting. It offers a syntax *familiar* to `C#`, `Java` and `Python` developers (via template arguments - `{0}` (positional), `{name}` (named)), extensive argument formatting options (numbers, lists, code style), and a set of text utilities — all while being significantly fast as the standard `fmt` package and even more! Typical usage of `sf` are: |
| 11 | +1. Create `e-mails`, `Messages` (`SMS`, `Telegram`, other `Notifications`) or other complicated text **based on templates** |
| 12 | +2. Create a complicated log text with specific argument formatting |
| 13 | +3. Use for **template-based src code generator** |
| 14 | +4. Other text proccessing |
16 | 15 |
|
17 | | -1. Text formatting with template using traditional for `C#, Python programmers style` - `{0}`, `{name}` that faster then `fmt` does: |
18 | | - |
19 | | -2. Additional text utilities: |
20 | | - - convert ***map to string*** using one of predefined formats (see `text_utils.go`) |
21 | | -3. Code Style formatting utilities |
22 | | - - convert `snake`/`kebab`/`camel` programming code to each other and vice versa (see `stringstyle_formatter.go`). |
23 | | -4. `StringFormatter` aka `sf` **is safe** (`SAST` and tests were running automatically on push) |
| 16 | +## ✨ 1 Features |
24 | 17 |
|
25 | | -### 1. Text formatting from templates |
| 18 | +🔤 Flexible Syntax: Supports both indexed / positional (`{0}`) and named (`{user}`) *placeholders* in templates. |
26 | 19 |
|
27 | | -#### 1.1 Description |
| 20 | +🎨 Advanced Formatting: Built-in directives for numbers (`HEX`, `BIN`), `floats`, `lists`, and code styles (camelCase, SNAKE_CASE). |
28 | 21 |
|
29 | | -This is a GO module for ***template text formatting in syntax like in C# or/and Python*** using: |
30 | | -- `{n}` , n here is a number to notes order of argument list to use i.e. `{0}`, `{1}` |
31 | | -- `{name}` to notes arguments by name i.e. `{name}`, `{last_name}`, `{address}` and so on ... |
| 22 | +🚀 Performance: Template formatting and slice conversion are even faster then `fmt`. |
32 | 23 |
|
33 | | -#### 1.2 Examples |
| 24 | +🛠 Utilities: Functions to convert `maps` and `slices` into strings with custom separators and formats. |
34 | 25 |
|
35 | | -##### 1.2.1 Format by arg order |
| 26 | +:man_technologist: Safe : `StringFormatter` aka `sf` **is safe** (`SAST` and tests are running automatically on push) |
36 | 27 |
|
37 | | -i.e. you have following template: `"Hello {0}, we are greeting you here: {1}!"` |
| 28 | +## 📦 2 Installation |
| 29 | + |
| 30 | +```bash |
| 31 | +go get github.com/Wissance/stringFormatter |
| 32 | +``` |
38 | 33 |
|
39 | | -if you call Format with args "manager" and "salesApp" : |
| 34 | +## 🚀 3 Usage |
| 35 | + |
| 36 | +### 3.1 Template Formatting |
| 37 | + |
| 38 | +#### 3.1.1 By Argument Order (Format) |
| 39 | +The Format function replaces `{n}` placeholders with the corresponding argument in the provided order. |
40 | 40 |
|
41 | 41 | ```go |
42 | | -formattedStr := stringFormatter.Format("Hello {0}, we are greeting you here: {1}!", "manager", "salesApp") |
43 | | -``` |
| 42 | +package main |
44 | 43 |
|
45 | | -you get string `"Hello manager, we are greeting you here: salesApp!"` |
| 44 | +import ( |
| 45 | + "fmt" |
| 46 | + sf "github.com/Wissance/stringFormatter" |
| 47 | +) |
46 | 48 |
|
47 | | -##### 1.2.2 Format by arg key |
| 49 | +func main() { |
| 50 | + template := "Hello, {0}! Your balance is {1} USD." |
| 51 | + result := sf.Format(template, "Alex", 2500) |
| 52 | + fmt.Println(result) |
| 53 | + // Output: Hello, Alex! Your balance is 2500 USD. |
| 54 | +} |
| 55 | +``` |
48 | 56 |
|
49 | | -i.e. you have following template: `"Hello {user} what are you doing here {app} ?"` |
| 57 | +#### 3.1.2 By Argument Name (FormatComplex) |
| 58 | +The FormatComplex function uses a `map[string]any` to replace named placeholders like `{key}`. |
50 | 59 |
|
51 | | -if you call `FormatComplex` with args `"vpupkin"` and `"mn_console"` `FormatComplex("Hello {user} what are you doing here {app} ?", map[string]any{"user":"vpupkin", "app":"mn_console"})` |
| 60 | +```go |
| 61 | +package main |
52 | 62 |
|
53 | | -you get string `"Hello vpupkin what are you doing here mn_console ?"` |
| 63 | +import ( |
| 64 | + "fmt" |
| 65 | + sf "github.com/Wissance/stringFormatter" |
| 66 | +) |
54 | 67 |
|
55 | | -another example is: |
| 68 | +func main() { |
| 69 | + template := "User {user} (ID: {id}) logged into {app}." |
| 70 | + args := map[string]any{ |
| 71 | + "user": "john_doe", |
| 72 | + "id": 12345, |
| 73 | + "app": "dashboard", |
| 74 | + } |
| 75 | + result := sf.FormatComplex(template, args) |
| 76 | + fmt.Println(result) |
| 77 | + // Output: User john_doe (ID: 12345) logged into dashboard. |
| 78 | +} |
| 79 | +``` |
| 80 | + |
| 81 | +### 3.2 Advanced Argument Formatting |
| 82 | +You can control how arguments are displayed by adding a colon (:) and a format specifier to the placeholder. |
| 83 | + |
| 84 | +| Type | Specifier | Description | Example Template | Example Value | Output | |
| 85 | +| :--- | :--- | :--- | :--- | :--- | :--- | |
| 86 | +| **Numbers** | `:B` | Binary (without padding) | `"{0:B}"` | `15` | `1111` | |
| 87 | +| | `:B8` | Binary with 8-digit padding | `"{0:B8}"` | `15` | `00001111` | |
| 88 | +| | `:X` | Hexadecimal (lowercase) | `"{0:X}"` | `250` | `fa` | |
| 89 | +| | `:X4` | Hexadecimal with 4-digit padding | `"{0:X4}"` | `250` | `00fa` | |
| 90 | +| | `:o` | Octal | `"{0:o}"` | `11` | `14` | |
| 91 | +| **Floating Point** | `:F` | Default float format | `"{0:F}"` | `10.4567890` | `10.456789` | |
| 92 | +| | `:F2` | Float with 2 decimal places | `"{0:F2}"` | `10.4567890` | `10.46` | |
| 93 | +| | `:F4` | Float with 4 decimal places | `"{0:F4}"` | `10.4567890` | `10.4568` | |
| 94 | +| | `:F8` | Float with 8 decimal places | `"{0:F8}"` | `10.4567890` | `10.45678900` | |
| 95 | +| | `:E2` | Scientific notation | `"{0:E2}"` | `191.0478` | `1.91e+02` | |
| 96 | +| **Percentage** | `:P100` | Percentage (multiply by 100) | `"{0:P100}"` | `12` | `12%` | |
| 97 | +| **Lists (Slices)** | `:L-` | Join with hyphen | `"{0:L-}"` | `[1 2 3]` | `1-2-3` | |
| 98 | +| | `:L, ` | Join with comma and space | `"{0:L, }"` | `[1 2 3]` | `1, 2, 3` | |
| 99 | +| **Code Styles** | `:c:snake` | Convert to snake_case | `"{0:c:snake}"` | `myFunc` | `my_func` | |
| 100 | +| | `:c:Snake` | Convert to Snake_Case (PascalSnake) | `"{0:c:Snake}"` | `myFunc` | `My_Func` | |
| 101 | +| | `:c:SNAKE` | Convert to SNAKE_CASE (upper) | `"{0:c:SNAKE}"` | `read-timeout` | `READ_TIMEOUT` | |
| 102 | +| | `:c:camel` | Convert to camelCase | `"{0:c:camel}"` | `my_variable` | `myVariable` | |
| 103 | +| | `:c:Camel` | Convert to CamelCase (PascalCase) | `"{0:c:Camel}"` | `my_variable` | `MyVariable` | |
| 104 | +| | `:c:kebab` | Convert to kebab-case | `"{0:c:kebab}"` | `myVariable` | `my-variable` | |
| 105 | +| | `:c:Kebab` | Convert to Kebab-Case (PascalKebab) | `"{0:c:Kebab}"` | `myVariable` | `My-Variable` | |
| 106 | +| | `:c:KEBAB` | Convert to KEBAB-CASE (upper) | `"{0:c:KEBAB}"` | `myVariable` | `MY-VARIABLE` | |
56 | 107 |
|
57 | 108 | ```go |
58 | | -strFormatResult = stringFormatter.FormatComplex( |
59 | | - "Current app settings are: ipAddr: {ipaddr}, port: {port}, use ssl: {ssl}.", |
60 | | - map[string]any{"ipaddr":"127.0.0.1", "port":5432, "ssl":false}, |
| 109 | +package main |
| 110 | + |
| 111 | +import ( |
| 112 | + "fmt" |
| 113 | + sf "github.com/Wissance/stringFormatter" |
61 | 114 | ) |
| 115 | + |
| 116 | +func main() { |
| 117 | + template := "Status 0x{0:X4} (binary: {0:B8}), temp: {1:F1}°C, items: {2:L, }." |
| 118 | + result := sf.Format(template, 475, 23.876, []int{1, 2, 3}) |
| 119 | + fmt.Println(result) |
| 120 | + // Output: Status 0x01DB (binary: 00011101), temp: 23.9°C, items: 1, 2, 3. |
| 121 | +} |
62 | 122 | ``` |
63 | | -a result will be: `"Current app settings are: ipAddr: 127.0.0.1, port: 5432, use ssl: false."`` |
64 | | - |
65 | | -##### 1.2.3 Advanced arguments formatting |
66 | | - |
67 | | -For more convenient lines formatting we should choose how arguments are representing in output text, |
68 | | -`stringFormatter` supports following format options: |
69 | | -1. Bin number formatting |
70 | | - - `{0:B}, 15 outputs -> 1111` |
71 | | - - `{0:B8}, 15 outputs -> 00001111` |
72 | | -2. Hex number formatting |
73 | | - - `{0:X}, 250 outputs -> fa` |
74 | | - - `{0:X4}, 250 outputs -> 00fa` |
75 | | -3. Oct number formatting |
76 | | - - `{0:o}, 11 outputs -> 14` |
77 | | -4. Float point number formatting |
78 | | - - `{0:E2}, 191.0478 outputs -> 1.91e+02` |
79 | | - - `{0:F}, 10.4567890 outputs -> 10.456789` |
80 | | - - `{0:F4}, 10.4567890 outputs -> 10.4568` |
81 | | - - `{0:F8}, 10.4567890 outputs -> 10.45678900` |
82 | | -5. Percentage output |
83 | | - - `{0:P100}, 12 outputs -> 12%` |
84 | | -6. Lists |
85 | | - - `{0:L-}, [1,2,3] outputs -> 1-2-3` |
86 | | - - `{0:L, }, [1,2,3] outputs -> 1, 2, 3` |
87 | | -7. Code |
88 | | - - `{0:c:snake}, myFunc outputs -> my_func` |
89 | | - - `{0:c:Snake}, myFunc outputs -> My_func` |
90 | | - - `{0:c:SNAKE}, read-timeout outputs -> READ_TIMEOUT` |
91 | | - - `{0:c:camel}, my_variable outputs -> myVariable` |
92 | | - - `{0:c:Camel}, my_variable outputs -> MyVariable` |
93 | | - |
94 | | -##### 1.2.4 Benchmarks of the Format and FormatComplex functions |
95 | | - |
96 | | -benchmark could be running using following commands from command line: |
97 | | -* to see `Format` result - `go test -bench=Format -benchmem -cpu 1` |
98 | | -* to see `fmt` result - `go test -bench=Fmt -benchmem -cpu 1` |
99 | | - |
100 | | -### 2. Text utilities |
101 | | - |
102 | | -#### 2.1 Map to string utility |
103 | | - |
104 | | -`MapToString` function allows to convert map with primitive key to string using format, including key and value, e.g.: |
105 | | -* `{key} => {value}` |
106 | | -* `{key} : {value}` |
107 | | -* `{value}` |
108 | | - |
109 | | -For example: |
| 123 | + |
| 124 | +## 🛠 4 Text Utilities |
| 125 | + |
| 126 | +### 4.1 Map to String (MapToString) |
| 127 | +Converts a map with primitive keys to a formatted string. |
110 | 128 | ```go |
111 | 129 | options := map[string]any{ |
112 | | - "connectTimeout": 1000, |
113 | | - "useSsl": true, |
114 | | - "login": "sa", |
115 | | - "password": "sa", |
| 130 | + "host": "localhost", |
| 131 | + "port": 8080, |
| 132 | + "ssl": true, |
116 | 133 | } |
117 | 134 |
|
118 | | -str := stringFormatter.MapToString(&options, "{key} : {value}", ", ") |
119 | | -// NOTE: order of key-value pairs is not guranteed though |
120 | | -// str will be something like: |
121 | | -"connectTimeout : 1000, useSsl : true, login : sa, password : sa" |
| 135 | +str := sf.MapToString(&options, "{key} = {value}", "\n") |
| 136 | +// Possible output (key order is not guaranteed): |
| 137 | +// host = localhost |
| 138 | +// port = 8080 |
| 139 | +// ssl = true |
122 | 140 | ``` |
123 | 141 |
|
124 | | -#### 2.2 Benchmarks of the MapToString function |
| 142 | +### 4.2 Slice to String (SliceToString, SliceSameTypeToString) |
| 143 | +Converts slices to a string using a specified separator. |
125 | 144 |
|
126 | | -* to see `MapToStr` result - `go test -bench=MapToStr -benchmem -cpu 1` |
| 145 | +```go |
| 146 | +// For a slice of any type |
| 147 | +mixedSlice := []any{100, "text", 3.14} |
| 148 | +separator := " | " |
| 149 | +result1 := sf.SliceToString(&mixedSlice, &separator) |
| 150 | +// result1: "100 | text | 3.14" |
| 151 | + |
| 152 | +// For a typed slice |
| 153 | +numSlice := []int{10, 20, 30} |
| 154 | +result2 := sf.SliceSameTypeToString(&numSlice, &separator) |
| 155 | +// result2: "10 | 20 | 30" |
| 156 | +``` |
127 | 157 |
|
128 | | - |
| 158 | +## 📊 5 Benchmarks |
| 159 | +The library is optimized for high-load scenarios. Key benchmarks show significant performance gains (performance could be differ due to 1. different CPU architectures 2. statistics): |
129 | 160 |
|
130 | | -#### 2.3 Slice to string utility |
| 161 | +Formatting (Format) vs fmt.Sprintf: 3-5x faster for complex templates. |
| 162 | +Slices (SliceToString) vs manual fmt-based joining: from `2.5` faster up to 20 items. |
131 | 163 |
|
132 | | -`SliceToString` - function that converts slice with passed separation between items to string. |
133 | | -```go |
134 | | -slice := []any{100, "200", 300, "400", 500, 600, "700", 800, 1.09, "hello"} |
135 | | -separator := "," |
136 | | -result := stringFormatter.SliceToString(&slice, &separator) |
| 164 | +Run the benchmarks yourself: |
| 165 | +```bash |
| 166 | +go test -bench=Format -benchmem -cpu 1 |
| 167 | +go test -bench=Fmt -benchmem -cpu 1 |
| 168 | +go test -bench=MapToStr -benchmem -cpu 1 |
137 | 169 | ``` |
| 170 | +Some benchmark screenshots: |
138 | 171 |
|
139 | | -`SliceSameTypeToString` - function that converts typed slice to line with separator |
140 | | -```go |
141 | | -separator := ":" |
142 | | -numericSlice := []int{100, 200, 400, 800} |
143 | | -result := stringFormatter.SliceSameTypeToString(&numericSlice, &separator) |
144 | | -``` |
| 172 | +1. `Format` and `FormatComplex`: |
| 173 | + |
| 174 | + |
| 175 | +2. `MapToStr`: |
| 176 | + |
| 177 | + |
| 178 | +3. `SliceToStr`: |
| 179 | + |
145 | 180 |
|
146 | | -#### 2.4 Benchmarks of the SliceToString function |
| 181 | +## 📄 6 License |
| 182 | +This project is licensed under the MIT License - see the LICENSE file for details. |
147 | 183 |
|
148 | | -`sf` is rather fast then `fmt` 2.5 times (250%) faster on slice with 20 items, see benchmark: |
149 | | - |
| 184 | +## 🤝 7 Contributing |
| 185 | +Contributions are welcome! If you find a bug or have a feature suggestion, please open an issue or submit a pull request. |
150 | 186 |
|
151 | | -### 3. Contributors |
| 187 | +**Contributors:** |
152 | 188 |
|
153 | 189 | <a href="https://github.com/Wissance/stringFormatter/graphs/contributors"> |
154 | 190 | <img src="https://contrib.rocks/image?repo=Wissance/stringFormatter" /> |
|
0 commit comments