Newbie Question: How loop through a string and replace certain values?

agolangf · · 56 次点击    
<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: &#34;gBluvaDzAIHg97ATvDxqgjtO&#34; desired: &#34;********************gjtO&#34; </code></pre> <p>What&#39;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 := &#34;gBluvaDzAIHg97ATvDxqgjtO&#34; var token_array []string; // Loop through token for i, _ := range token { if i &gt;= len(token) - 4 { // If it&#39;s one of the last 4 digits, use the original character token_array = append(token_array, string(token[i])) } else { // If it&#39;s not, use an asterisk token_array = append(token_array, &#34;*&#34;) } } fmt.Println(&#34;Token: %v&#34;, strings.Join(token_array[:], &#34;&#34;)) </code></pre> <hr/>**评论:**<br/><br/>joncalhoun: <pre><p>Strings are immutable, meaning you can&#39;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&#39;s perfect!</p> <p>1 small follow-up. You had used</p> <pre><code>b[i] = &#39;*&#39; </code></pre> <p>which I casually changed to </p> <pre><code>b[i] = &#34;*&#34; </code></pre> <p>Which throws error</p> <pre><code>cannot use &#34;*&#34; (type string) as type byte in assignment </code></pre> <p>What&#39;s the real difference between single and double quotes here? Are both not strings?</p></pre>joncalhoun: <pre><p>No. The <code>&#39;*&#39;</code> is a byte, whereas <code>&#34;*&#34;</code> is a string composed of a byte slice of length 1 (plus some other data).</p> <p>In other words, <code>&#34;*&#34;</code> is conceptually similar to <code>[]byte{&#39;*&#39;}</code>.</p> <p>The difference is subtle, and most of the time you probably don&#39;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>&#39;</code> and <code>&#34;</code> very similarly. </p></pre>ar1819: <pre><p>Actually <code>&#39;*&#39;</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&#39;ll need.</p></pre>AllThatJellyNoToast: <pre><p>Thanks a bunch. Yeah I&#39;m coming over from ruby where <code>&#39;</code> and <code>&#34;</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 ( &#34;fmt&#34; &#34;strings&#34; ) func main() { str := &#34;hello123abc&#34; fmt.Println(mask(str)) } func mask(s string) string { if len(s) &lt;= 4 { return s } return strings.Repeat(&#34;*&#34;, 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&#39;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>&#34;*****…&#34;</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{&#39;*&#39;}, len(s))</code> and then overwrites the last 4 bytes from <code>s</code> becomes faster.</p></pre>
56 次点击  
加入收藏 微博
暂无回复
添加一条新回复 (您需要 登录 后才能回复 没有账号 ?)
  • 请尽量让自己的回复能够对别人有帮助
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`
  • 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
  • 图片支持拖拽、截图粘贴等方式上传