<p>EDIT: agh, typo in the question: How <strong>to</strong> loop through...</p>
<p>I have a random string of characters (e.g. an api token), and I want to redact all but the last 4 characters so I can safely print it in my app log for security reasons</p>
<p>e.g.</p>
<pre><code>original: "gBluvaDzAIHg97ATvDxqgjtO"
desired: "********************gjtO"
</code></pre>
<p>What's the most efficient way to write this? </p>
<p>I came up with the below but it feels inefficient, so was hoping to get some guidance on how to do it more succinctly.</p>
<p>Thanks!</p>
<pre><code> token := "gBluvaDzAIHg97ATvDxqgjtO"
var token_array []string;
// Loop through token
for i, _ := range token {
if i >= len(token) - 4 {
// If it's one of the last 4 digits, use the original character
token_array = append(token_array, string(token[i]))
} else {
// If it's not, use an asterisk
token_array = append(token_array, "*")
}
}
fmt.Println("Token: %v", strings.Join(token_array[:], ""))
</code></pre>
<hr/>**评论:**<br/><br/>joncalhoun: <pre><p>Strings are immutable, meaning you can't alter them in Go. </p>
<p>Instead you will need to create a new string, much like you are doing. That said, you can do this a little simpler with something like this: <a href="https://play.golang.org/p/ZRKxTyLGhk" rel="nofollow">https://play.golang.org/p/ZRKxTyLGhk</a></p></pre>AllThatJellyNoToast: <pre><p>Thanks, that's perfect!</p>
<p>1 small follow-up. You had used</p>
<pre><code>b[i] = '*'
</code></pre>
<p>which I casually changed to </p>
<pre><code>b[i] = "*"
</code></pre>
<p>Which throws error</p>
<pre><code>cannot use "*" (type string) as type byte in assignment
</code></pre>
<p>What's the real difference between single and double quotes here? Are both not strings?</p></pre>joncalhoun: <pre><p>No. The <code>'*'</code> is a byte, whereas <code>"*"</code> is a string composed of a byte slice of length 1 (plus some other data).</p>
<p>In other words, <code>"*"</code> is conceptually similar to <code>[]byte{'*'}</code>.</p>
<p>The difference is subtle, and most of the time you probably don't really need to think about it, but it is important in this case. It is also different than many other languages that allow you to use <code>'</code> and <code>"</code> very similarly. </p></pre>ar1819: <pre><p>Actually <code>'*'</code> is untyped rune or int32. The interesting thing is that it can be implicitly cast to the int16 or int8 type. But you should also remember that symbol can be a UTF-8 symbol - and if you try to represent it using byte type. bad things will happen. Case in the point: <a href="https://play.golang.org/p/YthQootOoj" rel="nofollow">https://play.golang.org/p/YthQootOoj</a></p>
<p>BUT! Go slices can be converted from strings and vice versa - the Unicode symbol will just occupy the 1-2-4 bytes it'll need.</p></pre>AllThatJellyNoToast: <pre><p>Thanks a bunch. Yeah I'm coming over from ruby where <code>'</code> and <code>"</code> are almost identical (except that the latter allows interpolation). </p>
<p>I have to get into the mindset of thinking about what <em>type</em> each variable is, which is probably been the most difficult part of the transition</p></pre>natefinch: <pre><p>The strings package is your friend.<br/>
<a href="https://play.golang.org/p/E4k4zT9ATK" rel="nofollow">https://play.golang.org/p/E4k4zT9ATK</a></p>
<pre><code>package main
import (
"fmt"
"strings"
)
func main() {
str := "hello123abc"
fmt.Println(mask(str))
}
func mask(s string) string {
if len(s) <= 4 {
return s
}
return strings.Repeat("*", len(s)-4) + s[len(s)-4:]
}
</code></pre></pre>dchapes: <pre><p>[Of course, unless something like this is in a critical hot-path the best solution is likely the one that is easiest to read, understand, and maintain rather than what a benchmark says; so unless you're curious ignore this completely :)]</p>
<p>Using <code>strings.Repeat</code> was my first thought as well, but I was curious so I ran some benchmarks and compared a few solutions. Using <code>strings.Repeat</code> like this is slower and uses more memory in all cases compared with using <a href="https://play.golang.org/p/ZRKxTyLGhk" rel="nofollow"><code>[]byte</code> loop with a final <code>string</code> cast</a> as given previously.</p>
<p>Minor gains can be made with fixed <code>"*****…"</code> constant string sliced in as needed (e.g. <code>return mask[:i] + s[i:]</code>) but only between ~32 bytes and the length of the constant; if the input token is known to always be of a fixed size this may be the fastest and easiest solution. After ~96 bytes a variation on the <code>[]byte</code> loop that starts with <code>bytes.Repeat([]byte{'*'}, len(s))</code> and then overwrites the last 4 bytes from <code>s</code> becomes faster.</p></pre>
这是一个分享于 的资源,其中的信息可能已经有所发展或是发生改变。
入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889
- 请尽量让自己的回复能够对别人有帮助
- 支持 Markdown 格式, **粗体**、~~删除线~~、
`单行代码`
- 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
- 图片支持拖拽、截图粘贴等方式上传