import (
"net/url"
"strings"
)
// 可以通过修改底层url.QueryEscape代码获得更高的效率,很简单
func encodeURIComponent(str string) string {
r := url.QueryEscape(str)
r = strings.Replace(r, "+", "%20", -1)
return r
}
go的url.QueryEscape与js的encodeURIComponent是不一样的,主要体现在对空格的处理,此函数编码后的字符串可以被js的decodeURIComponent正确还原
测试代码如下:
foo(";,/?:@&=+$", "%3B%2C%2F%3F%3A%40%26%3D%2B%24")
foo("-_.!~*'()", "-_.!~*'()")
foo("#", "%23")
foo("ABC abc 123", "ABC%20abc%20123")
foo("hello java", "hello%20java")
foo("~`!@#£€$()*^&°%§¥¢?.,<>'\";:/|[]{}=+_- ", "~%60!%40%23%C3%82%C2%A3%C3%A2%E2%80%9A%C2%AC%24()*%5E%26%C3%82%C2%B0%25%C3%82%C2%A7%C3%82%C2%A5%C3%82%C2%A2%3F.%2C%3C%3E'%22%3B%3A%2F%7C%5B%5D%7B%7D%3D%2B_-%20")
foo("#this is a test", "%23this%20is%20a%20test")
foo("#foo bar$", "%23foo%20bar%24")
foo("test with different chars like çşöüğİı", "test%20with%20different%20chars%20like%20%C3%83%C2%A7%C3%85%C5%B8%C3%83%C2%B6%C3%83%C2%BC%C3%84%C5%B8%C3%84%C2%B0%C3%84%C2%B1")
foo("$ %20F%20@", "%24%20%2520F%2520%40")
foo(" %20F %20 +", "%20%2520F%20%2520%20%2B")
foo("%40F%20F%10F", "%2540F%2520F%2510F")
foo(" + %20 + ", "%20%2B%20%2520%20%2B%20")
foo("%20 %20 %20 %20F", "%2520%20%2520%20%2520%20%2520F")
foo("'%20F'", "'%2520F'")
foo("@%40@", "%40%2540%40")
foo(" test ", "%20test%20")
foo("$#%23#$", "%24%23%2523%23%24")
foo(" %20 ", "%20%20%20%2520%20%20%20")
foo("^â%5E", "%5E%C3%83%C2%A2%255E")
foo("({foo &%26 bar})", "(%7Bfoo%20%26%2526%20bar%7D)")
foo("\uD800\uDFFF", "%F0%90%8F%BF")
foo("中国", "%E4%B8%AD%E5%9B%BD")
function foo(src, dist) {
const r = encodeURIComponent(src)
if (r !== dist) {
console.log('enc:', src, dist, r)
}
const de = decodeURIComponent(dist)
if(de !== src){
console.log('dec:', dist, src, r)
}
}
const str = "\uD800\uDFFF"
console.log(str.length)
console.log(Buffer.from(str))
foo("({foo &%26 bar})","%28%7Bfoo%20%26%2526%20bar%7D%29")
下面是go语言的测试代码:
package main
import (
"fmt"
"net/url"
"strings"
)
func encodeURIComponent(str string) string {
r := url.QueryEscape(str)
r = strings.Replace(r, "+", "%20", -1)
return r
}
func paif(err error) {
if err != nil {
panic(err)
}
}
func main() {
// fmt.Println("\UD800DFFF")
// foo("\uD800\uDFFF", )
fmt.Println("\xe4\xb8\x96")
r, err := url.QueryUnescape("%F0%90%8F%BF")
paif(err)
fmt.Println("rrr:", r)
fmt.Println("r222:", encodeURIComponent(r))
foo(";,/?:@&=+$", "%3B%2C%2F%3F%3A%40%26%3D%2B%24")
foo("-_.!~*'()", "-_.!~*'()")
foo("#", "%23")
foo("ABC abc 123", "ABC%20abc%20123")
foo("hello java", "hello%20java")
foo("~`!@#£€$()*^&°%§¥¢?.,<>'\";:/|[]{}=+_- ", "~%60!%40%23%C3%82%C2%A3%C3%A2%E2%80%9A%C2%AC%24()*%5E%26%C3%82%C2%B0%25%C3%82%C2%A7%C3%82%C2%A5%C3%82%C2%A2%3F.%2C%3C%3E'%22%3B%3A%2F%7C%5B%5D%7B%7D%3D%2B_-%20")
foo("#this is a test", "%23this%20is%20a%20test")
foo("#foo bar$", "%23foo%20bar%24")
foo("test with different chars like çşöüğİı", "test%20with%20different%20chars%20like%20%C3%83%C2%A7%C3%85%C5%B8%C3%83%C2%B6%C3%83%C2%BC%C3%84%C5%B8%C3%84%C2%B0%C3%84%C2%B1")
foo("$ %20F%20@", "%24%20%2520F%2520%40")
foo(" %20F %20 +", "%20%2520F%20%2520%20%2B")
foo("%40F%20F%10F", "%2540F%2520F%2510F")
foo(" + %20 + ", "%20%2B%20%2520%20%2B%20")
foo("%20 %20 %20 %20F", "%2520%20%2520%20%2520%20%2520F")
foo("'%20F'", "'%2520F'")
foo("@%40@", "%40%2540%40")
foo(" test ", "%20test%20")
foo("$#%23#$", "%24%23%2523%23%24")
foo(" %20 ", "%20%20%20%2520%20%20%20")
foo("^â%5E", "%5E%C3%83%C2%A2%255E")
foo("({foo &%26 bar})", "(%7Bfoo%20%26%2526%20bar%7D)")
// foo("\uD800\uDFFF", "%F0%90%8F%BF")
// foo("\xD8\x00\xDF\xFF", "%F0%90%8F%BF")
foo("中国", "%E4%B8%AD%E5%9B%BD")
}
func foo(src string, dist string) {
r := url.QueryEscape(src)
r = strings.Replace(r, "+", "%20", -1)
if r != dist {
fmt.Printf("ensrc:%s\ngo:%s\njs:%s\n\n", src, r, dist)
}
r, err := url.QueryUnescape(dist)
paif(err)
if r != src {
fmt.Printf("desrc:%s\ngo:%s\njs:%s\n\n", src, r, dist)
}
}