How to insert a Character every X Characters in a String in Golang?

huangapple go评论78阅读模式
英文:

How to insert a Character every X Characters in a String in Golang?

问题

目标: 在 Golang 中的字符串中每隔 x 个字符插入一个字符

输入: helloworldhelloworldhelloworld

期望输出: hello-world-hello-world-hello-world

尝试

尝试一

package main

import (
	"fmt"
	"strings"
)

func main() {
	s := "helloworldhelloworldhelloworld"

	s = strings.Replace(s, "world", "-", -1)
	fmt.Println(s)
}

结果为:hello-hello-hello-


尝试二

  1. 计算字符数
  2. 循环
  3. 如果 X=5,则插入 -

尝试三

  1. 使用扫描和连接

问题

尝试二和尝试三目前没有包含代码片段的原因是,我还在思考在 Golang 中的字符串中每隔 X 个字符插入一个字符应该使用什么方法。

英文:

Aim: to insert a character every x characters in a string in Golang

Input: helloworldhelloworldhelloworld

Expected Output: hello-world-hello-world-hello-world

Attempts

Attempt one

package main

import (
	"fmt"
	"strings"
)

func main() {
	s := "helloworldhelloworldhelloworld"

	s = strings.Replace(s, "world", ",", -1)
	fmt.Println(s)
}

results in: hello,hello,hello,


Attempt two

  1. Count number of characters
  2. For loop
  3. If X=5 then insert a -

Attempt three

  1. Scan combined with join

Problem

The reason that attempts two and three do not contain code snippets at the moment is that I am still thinking what approach should be used to insert a character every X characters in a string in Golang.

答案1

得分: 10

这个函数只是在每第N个元素之间插入'-'符号。

func insertNth(s string, n int) string {
    var buffer bytes.Buffer
    var n_1 = n - 1
    var l_1 = len(s) - 1
    for i, rune := range s {
        buffer.WriteRune(rune)
        if i % n == n_1 && i != l_1  {
            buffer.WriteRune('-')
        }
    }
    return buffer.String()
}

函数的作用是将字符串s中的每第N个元素之间插入'-'符号,并返回修改后的字符串。

英文:

https://play.golang.org/p/HEGbe7radf

This function just inserts '-' each Nth element

func insertNth(s string,n int) string {
    var buffer bytes.Buffer
    var n_1 = n - 1
    var l_1 = len(s) - 1
    for i,rune := range s {
   	   buffer.WriteRune(rune)
	   if i % n == n_1 && i != l_1  {
		  buffer.WriteRune('-')
	   }
    }
	return buffer.String()
}

答案2

得分: 4

我觉得以下解决方案值得一提:

package main

import "fmt"

var s = "helloworldhelloworldhelloworld"

func main() {
    for i := 5; i < len(s); i += 6 {
        s = s[:i] + "-" + s[i:]
    }
    fmt.Println(s)
}

链接:https://play.golang.org/p/aMXOTgiNHf

英文:

I feel the following solution is worth mentioning:

package main

import &quot;fmt&quot;

var s = &quot;helloworldhelloworldhelloworld&quot;

func main() {
	for i := 5; i &lt; len(s); i += 6 {
		s = s[:i] + &quot;-&quot; + s[i:]
	}
	fmt.Println(s)
}

https://play.golang.org/p/aMXOTgiNHf

答案3

得分: 2

根据Go文档,字符串是一个只读的字节切片。考虑到这一点,会出现一个问题,那就是你使用的字符集是什么?你可以在这里看到一些例子,展示了一些奇怪的情况。

尽管存在复杂性,但仍然有一个简单的答案:

s = strings.Replace(s, "hello", "hello-", -1)
s = strings.Replace(s, "world", "world-", -1)
英文:

According to the Go documentation strings are a read only Slice of bytes.. With that in mind there is an issue that comes up. What character set are you using? You can see some examples of where things get weird here and here.

Despite the complexity there still is a simple answer

s = strings.Replace(s, &quot;hello&quot;, &quot;hello-&quot;, -1)
s = strings.Replace(s, &quot;world&quot;, &quot;world-&quot;, -1)

答案4

得分: 1

我的翻译:

我的看法:

import (
	"fmt"
	"regexp"
)

const s = "helloworldhelloworldhelloworld"

func Attempt1(s string) string {
	var re = regexp.MustCompile(`(\Bhello|\Bworld)`)
	return re.ReplaceAllString(s, "-$1")
}

func Attempt2(s string) string {
	const chunkLen = len("hello")
	out := make([]rune, len(s)+len(s)/chunkLen)
	i, j := 1, 0
	for _, c := range s {
		out[j] = c
		if i == len(s) {
			break
		}
		j++
		if i%chunkLen == 0 {
			out[j] = '-'
			j++
		}
		i++
	}
	return string(out)
}

func main() {
	fmt.Println(Attempt1(s))
	fmt.Println(Attempt2(s))
}

Playground链接

我应该补充说明,虽然可以实现“方法3”——将源字符串拆分为五个字符的块,然后使用“-”字符连接这些块,但仍需要像Attempt2()一样逐个字符扫描源字符串;因此,如果你仔细看,你会发现存储块列表然后连接它们会进行更多的操作,而没有真正的收益(还会增加内存占用等)。

英文:

My take:

<pre><code>
import (
"fmt"
"regexp"
)

const s = "helloworldhelloworldhelloworld"

func Attempt1(s string) string {
var re = regexp.MustCompile((\Bhello|\Bworld))
return re.ReplaceAllString(s, "-$1")
}

func Attempt2(s string) string {
const chunkLen = len("hello")
out := make([]rune, len(s)+len(s)/chunkLen)
i, j := 1, 0
for _, c := range s {
out[j] = c
if i == len(s) {
break
}
j++
if i%chunkLen == 0 {
out[j] = '-'
j++
}
i++
}
return string(out)
}

func main() {
fmt.Println(Attempt1(s))
fmt.Println(Attempt2(s))
}
</code></pre>

<kbd>Playground link</kbd>

I should add that while it would be possible to implement
"approach 3" &mdash; that "split the source string in chunks of
five characters then join the chunks using the '-' character" one, &mdash;
it would still require scanning the source string rune-by-rune as my Attempt2() does; so if you squint at it, you'll see that storing
a list of chunks and then joining them is doing more operations for
no real gain (and bigger memory footprint etc).

答案5

得分: 0

如果您知道您的字符串可以被5整除,那么这也可以是一个解决方案。但与其他一些已发布的解决方案相比,效率肯定较低。

package main

import (
	"fmt"
	"regexp"
	"strings"
)

func main() {
	fmt.Println(InsertEvery5("HelloWorld", "-"))
}

// 仅在 len(str) mod 5 等于 0 时有效
func InsertEvery5(str string, insert string) string {
	re := regexp.MustCompile(`.{5}`) // 每5个字符
	parts := re.FindAllString(str, -1) // 将字符串分割为5个字符的块。
	return strings.Join(parts, insert) // 将字符串重新组合
}
英文:

If you know your string is divisible by 5, then this could also be a solution. Definitely less efficient though than some of the other solutions posted.

package main

import (
	&quot;fmt&quot;
	&quot;regexp&quot;
	&quot;strings&quot;
)

func main() {
	fmt.Println(InsertEvery5(&quot;HelloWorld&quot;, &quot;-&quot;))
}

// Only works if len(str) mod 5 is 0
func InsertEvery5(str string, insert string) string {
	re := regexp.MustCompile(`.{5}`) // Every 5 chars
	parts := re.FindAllString(str, -1) // Split the string into 5 chars blocks.
	return strings.Join(parts, insert) // Put the string back together
}

答案6

得分: 0

我的翻译如下:

我的看法是,我需要在长字符串中添加换行符(不止一个字符)来进行换行。

func InsertNewLines(s string, n int) string {
    var r = regexp.MustCompile("(.{" + strconv.Itoa(n) + "})")
    return r.ReplaceAllString(s, "$1<wbr />")
}
英文:

My take. I needed to add new lines (more than a single character) to long strings to wrap them.

func InsertNewLines(s string, n int) string {
	var r = regexp.MustCompile(&quot;(.{&quot; + strconv.Itoa(n) + &quot;})&quot;)
	return r.ReplaceAllString(s, &quot;$1&lt;wbr /&gt;&quot;)
}

答案7

得分: 0

预先分配内存并使用copy比迭代每个字符要快。

func insertNthCopy(in, sep string, n int) string {
	count := len(in) / n // 分割的行数
	split := make([]byte, len(in)+len(sep)*count)
	i, s := 0, 0

	for ; i < count*n; i, s = i+n, s+n+len(sep) {
		copy(split[s:], in[i:i+n])
		copy(split[s+n:], sep)
	}

	copy(split[s:], in[i:]) // 复制剩余的部分(如果有)

	return string(split)
}

与提供的示例字符串相比,大约快了六倍:

cpu: Intel(R) Core(TM) i7-8550U CPU @ 1.80GHz
Benchmark_insertNthCopy
Benchmark_insertNthCopy-8   	12404311	        85.11 ns/op
Benchmark_insertNth
Benchmark_insertNth-8          	 2269458	       524.5 ns/op
英文:

Pre-allocating memory and using copy is faster than iteration over every single character.

https://go.dev/play/p/NqVYnOJGRLP

func insertNthCopy(in, sep string, n int) string {
	count := len(in) / n // amount of lines to split
	split := make([]byte, len(in)+len(sep)*count)
	i, s := 0, 0

	for ; i &lt; count*n; i, s = i+n, s+n+len(sep) {
		copy(split[s:], in[i:i+n])
		copy(split[s+n:], sep)
	}

	copy(split[s:], in[i:]) // copy remainder if any

	return string(split)
}

About six times faster than the accepted answer with provided sample string:

cpu: Intel(R) Core(TM) i7-8550U CPU @ 1.80GHz
Benchmark_insertNthCopy
Benchmark_insertNthCopy-8   	12404311	        85.11 ns/op
Benchmark_insertNth
Benchmark_insertNth-8          	 2269458	       524.5 ns/op

huangapple
  • 本文由 发表于 2015年11月10日 23:09:57
  • 转载请务必保留本文链接:https://go.coder-hub.com/33633168.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定