Golang : Warp text string by number of characters or runes example
Problem:
You have a long text string and you want to wrap the text according to a given number of characters per line instead of number of words. This is to make the output fit nicely to display on terminal or web page. How to do that?
Solution:
This is a simple and primitive wrap by number of characters per line solution that should work for most cases.
convert the text string into a slice of characters.
push out the characters into a line according to the given limit/length and append each line with \r\n
Here you go!
package main
import (
"fmt"
"github.com/buger/goterm"
)
// Limits a string to X number of characters.
func char_wrap(s string, limit int) string {
var charSlice []rune
// push characters to slice
for _, char := range s {
charSlice = append(charSlice, char)
}
var result string = ""
for len(charSlice) >= 1 {
// convert slice/array back to string
// but insert \r\n at specified limit
result = result + string(charSlice[:limit]) + "\r\n"
// discard the elements that were copied over to result
charSlice = charSlice[limit:]
// change the limit
// to cater for the last few words in
//
if len(charSlice) < limit {
limit = len(charSlice)
}
}
return result
}
func main() {
str := "ReadAtLeast reads from r into buf until it has read at least min bytes. It returns the number of bytes copied and an error if fewer bytes were read. The error is EOF only if no bytes were read. If an EOF happens after reading fewer than min bytes, ReadAtLeast returns ErrUnexpectedEOF. If min is greater than the length of buf, ReadAtLeast returns ErrShortBuffer. On return, n >= min if and only if err == nil."
fmt.Printf("Original : \n[%s]\n\n", str)
// wrap at 80 characters
fmt.Printf("80 characters : \n%s\n", char_wrap(str, 80))
// wrap according to terminal width
terminalWidth := goterm.Width()
fmt.Println("Terminal width is : ", terminalWidth)
fmt.Printf("%d characters : \n%s\n", terminalWidth, char_wrap(str, terminalWidth))
japaneseStr := "お客様からお預かりする貴重な金型を共有の財産と考え、金型の生産性向上や長寿命化にも重
点をおいています。 最新技術・機器を導入し、より品質の高いものを提供します。また古い金型に新しく息を吹き込む努力も惜しみません。 経年劣化よる摩耗やひび割れ・酸化した金型もメンテナンスします。"
fmt.Printf("Original : \n[%s]\n\n", japaneseStr)
// wrap at 20 runes
fmt.Printf("20 characters : \n%s\n", char_wrap(japaneseStr, 20))
fmt.Println("Terminal width is : ", terminalWidth)
fmt.Printf("%d characters : \n%s\n", terminalWidth, char_wrap(japaneseStr, terminalWidth))
}
Output :
Original : [ReadAtLeast reads from r into buf until it has read at least min bytes. It returns the number of bytes copied and an error if fewer bytes were read. The error is EOF only if no bytes were read. If an EOF happens after reading fewer than min bytes, ReadAtLeast returns ErrUnexpectedEOF. If min is greater than the length of buf, ReadAtLeast returns ErrShortBuffer. On return, n >= min if and only if err == nil.]
80 characters :
ReadAtLeast reads from r into buf until it has read at least min bytes. It retur
ns the number of bytes copied and an error if fewer bytes were read. The error i
s EOF only if no bytes were read. If an EOF happens after reading fewer than min
bytes, ReadAtLeast returns ErrUnexpectedEOF. If min is greater than the length
of buf, ReadAtLeast returns ErrShortBuffer. On return, n >= min if and only if e
rr == nil.
Terminal width is : 109
109 characters :
ReadAtLeast reads from r into buf until it has read at least min bytes. It returns the number of bytes copied
and an error if fewer bytes were read. The error is EOF only if no bytes were read. If an EOF happens after
reading fewer than min bytes, ReadAtLeast returns ErrUnexpectedEOF. If min is greater than the length of buf,
ReadAtLeast returns ErrShortBuffer. On return, n >= min if and only if err == nil.
Original :
[お客様からお預かりする貴重な金型を共有の財産と考え、金型の生産性向上や長寿命化にも重点をおいています。 最新技術・機器を導入し、より品質の高いものを提供します。また古い金型に新しく息を吹き込む努力も惜しみません。 経年劣化よる摩耗やひび割れ・酸化した金型もメンテナンスします。]
20 characters :
お客様からお預かりする貴重な金型を共有の
財産と考え、金型の生産性向上や長寿命化に
も重点をおいています。 最新技術・機器を
導入し、より品質の高いものを提供します。
また古い金型に新しく息を吹き込む努力も惜
しみません。 経年劣化よる摩耗やひび割れ
・酸化した金型もメンテナンスします。
Terminal width is : 109
109 characters :
お客様からお預かりする貴重な金型を共有の財産と考え、金型の生産性向上や長寿命化にも重点をおいています。 最新技術・機器を導入し、より品質の高いも
のを提供します。また古い金型に新しく息を吹き込む努力も惜しみません。 経年
劣化よる摩耗やひび割れ・酸化した金型もメンテナンスします。
References:
https://www.socketloop.com/tutorials/golang-count-number-of-rune-in-string
https://www.socketloop.com/tutorials/golang-get-terminal-width-and-height-example
See also : Golang : Simple word wrap or line breaking example
By Adam Ng
IF you gain some knowledge or the information here solved your programming problem. Please consider donating to the less fortunate or some charities that you like. Apart from donation, planting trees, volunteering or reducing your carbon footprint will be great too.
Advertisement
Tutorials
+7.3k SSL : How to check if current certificate is sha1 or sha2 from command line
+20.7k Golang : For loop continue,break and range
+8.8k Golang : Serving HTTP and Websocket from different ports in a program example
+11.9k Golang : Simple client-server HMAC authentication without SSL example
+4.6k Nginx and PageSpeed build from source CentOS example
+8.3k Golang : Another camera capture GUI application with GTK and OpenCV
+19.6k Golang : How to get own program name during runtime ?
+8k Golang : Oanda bot with Telegram and RSI example
+18.3k Golang : Set, Get and List environment variables
+7.8k Golang : Multiplexer with net/http and map
+25.4k Golang : Convert IP address string to long ( unsigned 32-bit integer )
+8.7k Golang : automatically figure out array length(size) with three dots