From 2d7d50b7b89722d9845c60d469656314157a3e7d Mon Sep 17 00:00:00 2001
From: hyliang96 <hyliang96@hotmail.com>
Date: Sun, 27 Sep 2020 00:37:55 +0800
Subject: [PATCH] fix issue 22: replace ip4/ip6/domain with regexp with
 lookahead and lookback

---
 internal/app/cdn.go       |  3 +--
 internal/app/parse.go     | 23 +++++++++++++++++++++--
 internal/tools/replace.go | 23 ++++++++++++++++-------
 3 files changed, 38 insertions(+), 11 deletions(-)

diff --git a/internal/app/cdn.go b/internal/app/cdn.go
index 24af506..066d420 100644
--- a/internal/app/cdn.go
+++ b/internal/app/cdn.go
@@ -52,7 +52,6 @@ func find(cname string) string {
 
 func ReplaceCDNInString(str string) (result string) {
 	done := make(map[string]bool)
-
 	cnames := domainRe.FindAllString(str, -1)
 	result = str
 	for _, cname := range cnames {
@@ -61,7 +60,7 @@ func ReplaceCDNInString(str string) (result string) {
 			if _, found := done[cname]; found {
 				continue
 			}
-			result = tools.ReplaceAdd(result, cname, fmt.Sprintf("%s [%s]", cname, name))
+			result = tools.AddInfoDomain(result, cname, name)
 			done[cname] = true
 		}
 	}
diff --git a/internal/app/parse.go b/internal/app/parse.go
index 5fd252f..05987b4 100644
--- a/internal/app/parse.go
+++ b/internal/app/parse.go
@@ -56,6 +56,23 @@ func ParseIPs(ips []string) {
 	}
 }
 
+func RemoveRepeatedElement(arr []string) (newArr []string) {
+    newArr = make([]string, 0)
+    for i := 0; i < len(arr); i++ {
+        repeat := false
+        for j := i + 1; j < len(arr); j++ {
+            if arr[i] == arr[j] {
+                repeat = true
+                break
+            }
+        }
+        if !repeat {
+            newArr = append(newArr, arr[i])
+        }
+    }
+    return
+}
+
 func ReplaceIPInString(str string) (result string) {
 	db0 := db[0]
 	var db1 ipdb.IPDB
@@ -67,15 +84,17 @@ func ReplaceIPInString(str string) (result string) {
 
 	result = str
 	ip4s := tools.GetIP4FromString(str)
+	ip4s = RemoveRepeatedElement(ip4s)
 	for _, ip := range ip4s {
 		info := db0.Find(ip)
-		result = tools.ReplaceAdd(result, ip, formatResult(ip, info))
+		result = tools.AddInfoIp4(result, ip, info)
 	}
 
 	ip6s := tools.GetIP6FromString(str)
+	ip6s = RemoveRepeatedElement(ip6s)
 	for _, ip := range ip6s {
 		info := db1.Find(ip)
-		result = tools.ReplaceAdd(result, ip, formatResult(ip, info))
+		result = tools.AddInfoIp6(result, ip, info)
 	}
 	return
 }
diff --git a/internal/tools/replace.go b/internal/tools/replace.go
index 3930d12..1af42c9 100644
--- a/internal/tools/replace.go
+++ b/internal/tools/replace.go
@@ -2,14 +2,23 @@ package tools
 
 import (
 	"strings"
+	"regexp"
 )
 
-func ReplaceAdd(origin string, old string, new string) (result string) {
-	subLen := len(new) - len(old)
-	wanted := old + strings.Repeat(" ", subLen)
-	if strings.Contains(origin, wanted) {
-		result = strings.ReplaceAll(origin, wanted, new)
-	}
-	result = strings.ReplaceAll(origin, old, new)
+func AddInfoIp4(origin string, ip string, info string) (result string) {
+	re := regexp.MustCompile("(^|[^0-9.])(" + strings.ReplaceAll(ip, ".", "\\.") + ")($|[^0-9.])")
+	result = re.ReplaceAllString(origin, "$1$2"+" ["+info+"]$3")
 	return strings.TrimRight(result, " \t")
 }
+
+func AddInfoIp6(origin string, ip string, info string) (result string) {
+	re := regexp.MustCompile("(^|[^0-9a-fA-F:])(" + strings.ReplaceAll(ip, ".", "\\.") + ")($|[^0-9a-fA-F:])")
+	result = re.ReplaceAllString(origin, "$1$2"+" ["+info+"]$3")
+	return strings.TrimRight(result, " \t")
+}
+
+func AddInfoDomain(origin string, domain string, info string) (result string) {
+	re := regexp.MustCompile("(^|[^0-9a-zA-Z-])(" + strings.ReplaceAll(domain, ".", "\\.") + ")($|[^0-9a-zA-Z-\\.])")
+	result = re.ReplaceAllString(origin, "$1$2"+" ["+info+"]$3")
+	return strings.TrimRight(result, " \t")
+}
\ No newline at end of file