4 回答

TA貢獻1811條經(jīng)驗 獲得超4個贊
對于那些來這里尋找快速解決方案的人來說,有一個庫可以做到這一點:bluemonday。
包bluemonday提供了一種將 HTML 元素和屬性的白名單描述為策略的方法,并將該策略應用于來自可能包含標記的用戶的不受信任的字符串。所有不在白名單上的元素和屬性都將被刪除。
package main
import (
? ? "fmt"
? ? "github.com/microcosm-cc/bluemonday"
)
func main() {
? ? // Do this once for each unique policy, and use the policy for the life of the program
? ? // Policy creation/editing is not safe to use in multiple goroutines
? ? p := bluemonday.StripTagsPolicy()
? ? // The policy can then be used to sanitize lots of input and it is safe to use the policy in multiple goroutines
? ? html := p.Sanitize(
? ? ? ? `<a onblur="alert(secret)" >Google</a>`,
? ? )
? ? // Output:
? ? fmt.Println(html)
}
https://play.golang.org/p/jYARzNwPToZ

TA貢獻1801條經(jīng)驗 獲得超8個贊
正則表達式的問題
這是一個非常簡單的 RegEx 替換方法,它從字符串中格式良好的HTML中刪除 HTML 標記。
strip_html_regex.go
package main
import "regexp"
const regex = `<.*?>`
// This method uses a regular expresion to remove HTML tags.
func stripHtmlRegex(s string) string {
r := regexp.MustCompile(regex)
return r.ReplaceAllString(s, "")
}
注意:這不適用于格式錯誤的HTML。不要用這個。
更好的方法
由于 Go 中的字符串可以被視為字節(jié)的一部分,因此可以輕松遍歷字符串并查找不在 HTML 標記中的部分。當我們識別字符串的有效部分時,我們可以簡單地截取該部分的一部分并使用strings.Builder.
strip_html.go
package main
import (
"strings"
"unicode/utf8"
)
const (
htmlTagStart = 60 // Unicode `<`
htmlTagEnd = 62 // Unicode `>`
)
// Aggressively strips HTML tags from a string.
// It will only keep anything between `>` and `<`.
func stripHtmlTags(s string) string {
// Setup a string builder and allocate enough memory for the new string.
var builder strings.Builder
builder.Grow(len(s) + utf8.UTFMax)
in := false // True if we are inside an HTML tag.
start := 0 // The index of the previous start tag character `<`
end := 0 // The index of the previous end tag character `>`
for i, c := range s {
// If this is the last character and we are not in an HTML tag, save it.
if (i+1) == len(s) && end >= start {
builder.WriteString(s[end:])
}
// Keep going if the character is not `<` or `>`
if c != htmlTagStart && c != htmlTagEnd {
continue
}
if c == htmlTagStart {
// Only update the start if we are not in a tag.
// This make sure we strip out `<<br>` not just `<br>`
if !in {
start = i
}
in = true
// Write the valid string between the close and start of the two tags.
builder.WriteString(s[end:start])
continue
}
// else c == htmlTagEnd
in = false
end = i + 1
}
s = builder.String()
return s
}
如果我們使用 OP 的文本和一些格式錯誤的 HTML 運行這兩個函數(shù),您會發(fā)現(xiàn)結果不一致。
main.go
package main
import "fmt"
func main() {
s := "afsdf4534534!@@!!#<div>345345afsdf4534534!@@!!#</div>"
res := stripHtmlTags(s)
fmt.Println(res)
// Malformed HTML examples
fmt.Println("\n:: stripHTMLTags ::\n")
fmt.Println(stripHtmlTags("Do something <strong>bold</strong>."))
fmt.Println(stripHtmlTags("h1>I broke this</h1>"))
fmt.Println(stripHtmlTags("This is <a href='#'>>broken link</a>."))
fmt.Println(stripHtmlTags("I don't know ><where to <<em>start</em> this tag<."))
// Regex Malformed HTML examples
fmt.Println(":: stripHtmlRegex ::\n")
fmt.Println(stripHtmlRegex("Do something <strong>bold</strong>."))
fmt.Println(stripHtmlRegex("h1>I broke this</h1>"))
fmt.Println(stripHtmlRegex("This is <a href='#'>>broken link</a>."))
fmt.Println(stripHtmlRegex("I don't know ><where to <<em>start</em> this tag<."))
}
輸出:
afsdf4534534!@@!!#345345afsdf4534534!@@!!#
:: stripHTMLTags ::
Do something bold.
I broke this
This is broken link.
start this tag
:: stripHtmlRegex ::
Do something bold.
h1>I broke this
This is >broken link.
I don't know >start this tag<.
注意:RegEx 方法不會始終如一地刪除所有 HTML 標記。老實說,我不太擅長 RegEx,無法編寫 RegEx 匹配字符串來正確處理剝離 HTML。
基準
除了在剝離格式錯誤的 HTML 標簽方面更安全和更積極的優(yōu)勢之外,stripHtmlTags它比 . 快 4 倍左右stripHtmlRegex。
> go test -run=Calculate -bench=.
goos: windows
goarch: amd64
BenchmarkStripHtmlRegex-8 51516 22726 ns/op
BenchmarkStripHtmlTags-8 230678 5135 ns/op

TA貢獻1815條經(jīng)驗 獲得超13個贊
如果你想替換所有的 HTML 標簽,使用 strip of html 標簽。
匹配 HTML 標簽的正則表達式不是一個好主意。
package main
import (
"fmt"
"github.com/grokify/html-strip-tags-go"
)
func main() {
text := "afsdf4534534!@@!!#<div>345345afsdf4534534!@@!!#</div>"
stripped := strip.StripTags(text)
fmt.Println(text)
fmt.Println(stripped)
}

TA貢獻1789條經(jīng)驗 獲得超10個贊
我們已經(jīng)在生產(chǎn)中嘗試過這個,但在某些極端情況下,所提出的解決方案都沒有真正起作用。如果你需要一些強大的東西,請檢查 Go 內(nèi)部庫的未導出方法(html-strip-tags-go pkg 基本上是使用 BSD-3 許可證導出的)?;蛘?a >https://github.com/microcosm-cc/bluemonday是我們最終使用的非常流行的庫(也包括 BSD-3)。
=================================================
這里唯一的區(qū)別是由于len
對所有 utf-8 字符的字符串評估。對于使用的每個字符,它將返回 1-4 之間。所以len(è)
實際上會評估為2
.?為了解決這個問題,我們將把字符串轉(zhuǎn)換為rune
.
https://go.dev/play/p/xo7Mrx5qw-_J
// Aggressively strips HTML tags from a string.
// It will only keep anything between `>` and `<`.
func stripHTMLTags(s string) string {
? ? // Supports utf-8, since some char could take more than 1 byte. ie: len("è") -> 2
? ? d := []rune(s)
? ? // Setup a string builder and allocate enough memory for the new string.
? ? var builder strings.Builder
? ? builder.Grow(len(d) + utf8.UTFMax)
? ? in := false // True if we are inside an HTML tag.
? ? start := 0? // The index of the previous start tag character `<`
? ? end := 0? ? // The index of the previous end tag character `>`
? ? for i, c := range d {
? ? ? ? // If this is the last character and we are not in an HTML tag, save it.
? ? ? ? if (i+1) == len(d) && end >= start {
? ? ? ? ? ? builder.WriteString(s[end:])
? ? ? ? }
? ? ? ? // Keep going if the character is not `<` or `>`
? ? ? ? if c != htmlTagStart && c != htmlTagEnd {
? ? ? ? ? ? continue
? ? ? ? }
? ? ? ? if c == htmlTagStart {
? ? ? ? ? ? // Only update the start if we are not in a tag.
? ? ? ? ? ? // This make sure we strip out `<<br>` not just `<br>`
? ? ? ? ? ? if !in {
? ? ? ? ? ? ? ? start = i
? ? ? ? ? ? }
? ? ? ? ? ? in = true
? ? ? ? ? ? // Write the valid string between the close and start of the two tags.
? ? ? ? ? ? builder.WriteString(s[end:start])
? ? ? ? ? ? continue
? ? ? ? }
? ? ? ? // else c == htmlTagEnd
? ? ? ? in = false
? ? ? ? end = i + 1
? ? }
? ? s = builder.String()
? ? return s
}
- 4 回答
- 0 關注
- 480 瀏覽
添加回答
舉報