如何在golang中用空字符串替换所有html标签

时间:2019-03-07 04:34:03

标签: go

我试图用正则表达式模式<div> </div>替换golang中空字符串(“”)上的所有html标签,例如^[^.\/]*$/g ...,以匹配所有关闭标签。例如:</div>

我的解决方案:

package main

import (
    "fmt"
    "regexp"
)

const Template = `^[^.\/]*$/g`

func main() {
    r := regexp.MustCompile(Template)
    s := "afsdf4534534!@@!!#<div>345345afsdf4534534!@@!!#</div>"

    res := r.ReplaceAllString(s, "")
    fmt.Println(res)
}

但是输出相同的源字符串。怎么了?请帮忙。谢谢

预期结果应为:"afsdf4534534!@@!!#345345afsdf4534534!@@!!#"

4 个答案:

答案 0 :(得分:3)

如果要替换所有HTML标记,请使用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)
}

答案 1 :(得分:2)

对于那些来这里寻求快速解决方案的人,有一个图书馆可以这样做:bluemonday

Package 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)" href="http://www.google.com">Google</a>`,
    )

    // Output:
    // Google
    fmt.Println(html)
}

https://play.golang.org/p/jYARzNwPToZ

答案 2 :(得分:1)

RegEx的问题

这是一个非常简单的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中的字符串可以被视为字节的一部分,因此可以轻松遍历字符串并轻松查找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运行这两个函数,您将看到结果不一致。

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(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<."))
}

输出:

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标签外,stripHtmlTagsstripHtmlRegex快4倍。

> go test -run=Calculate -bench=.
goos: windows
goarch: amd64
BenchmarkStripHtmlRegex-8          51516             22726 ns/op
BenchmarkStripHtmlTags-8          230678              5135 ns/op

答案 3 :(得分:0)

从@Daniel Morelli 函数开始,我创建了另一个具有更多可能性的函数。 如果它对某人有用,我会在这里分享:

//CreateCleanWords takes a string and returns a string array with all words in string
// rules:
// words of lenght >= of minAcceptedLenght
// everything between < and > is discarded
// admitted characters: numbers, letters, and all characters in validRunes map
// words not present in wordBlackList map
// word separators are space or single quote (could be improved with a map of separators)
func CreateCleanWords(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)

    insideTag := false // True if we are inside an HTML tag.
    var c rune
    var managed bool = false
    var valid bool = false
    var finalWords []string
    var singleQuote rune = '\''
    var minAcceptedLenght = 4

    var wordBlackList map[string]bool = map[string]bool{
        "sull":  false,
        "sullo": false,
        "sulla": false,
        "sugli": false,
        "sulle": false,
        "alla":  false,
        "all":   false,
        "allo":  false,
        "agli":  false,
        "alle":  false,
        "dell":  false,
        "della": false,
        "dello": false,
        "degli": false,
        "delle": false,
        "dall":  false,
        "dalla": false,
        "dallo": false,
        "dalle": false,
        "dagli": false,
    }

    var validRunes map[rune]bool = map[rune]bool{
        'à': true,
        'è': true,
        'é': true,
        'ì': true,
        'ò': true,
        'ù': true,
        '€': true,
        '$': true,
        '£': true,
        '-': true,
    }

    for _, c = range s {

        managed = false
        valid = false

        //show := string(c)
        //fmt.Println(show)

        // found < from here on ignore characters
        if !managed && c == htmlTagStart {
            insideTag = true
            managed = true
            valid = false
        }
        // found > characters are valid now
        if !managed && c == htmlTagEnd {
            insideTag = false
            managed = true
            valid = false
        }

        // if we are inside an HTML tag, we don't check anything because we won't take anything
        // until we reach the tag end
        if !insideTag {
            if !managed && unicode.IsSpace(c) || c == singleQuote {
                // found space if I have a valid word let's add it to  word array
                // only bigger than 3 letters
                if builder.Len() >= minAcceptedLenght {
                    word := strings.ToLower((builder).String())
                    //first check if the word is not in a black list
                    if _, ok := wordBlackList[word]; !ok {
                        // the word is not in blacklist let's add to finalWords
                        finalWords = append(finalWords, word)
                    }

                }
                // make builder ready for next token
                builder.Reset()

                valid = false
                managed = true
            }

            // letters and digits are welvome
            if !managed {
                valid = unicode.IsLetter(c) || unicode.IsDigit(c)
                managed = valid
            }

            // other italian runes accepted
            if !managed {
                _, valid = validRunes[c]
            }

            if valid {
                builder.WriteRune(c)
            }
        }
    }
    // remember to check the last word after exiting from for!
    if builder.Len() > minAcceptedLenght {
        //first check if the word is not in a black list
        word := builder.String()
        if _, ok := wordBlackList[word]; !ok {
            // the word is not in blacklist let's add to finalWords
            finalWords = append(finalWords, word)
        }
        builder.Reset()

    }

    return finalWords
}