我有一个函数,将输入字符串格式化为html字符串格式

For example, lorem ipsum *dolor sit amet* consectetur **adipiscing** elit.

哪里
* is for <i>
** is for <b>

因此,输出字符串可能是:
Lorem ipsum <i>dolor sit amet</i>, consectetur <b>adipiscing</b> elit.

我写了这个功能:

val input = "Lorem ipsum *dolor sit amet*, consectetur **adipiscing** elit."

val tagMap = mapOf(
        '*' to "<i>",
        '♥' to "<b>",
        '♦' to "<s>"
)

val tagMapClose = mapOf(
        '*' to "</i>",
        '♥' to "</b>",
        '♦' to "</s>"
)

fun tagCheck(obj: String): String {
    var str = Regex("""\*\*""").replace(obj, "♥")
    str = Regex("""~~""").replace(str, "♦")
    str = Regex("""\*\*\*""").replace(str, "♥*")
    val charList = str.toList()
    var res = ""
    val indexMap = mutableMapOf<Int, String>()
    var ct = 0

    for ((tag, define) in tagMap) {
        val tagIndex = mutableListOf<Int>()
        var status = true
        for (char in charList) if (char == tag) tagIndex.add(charList.indexOf(char))
        ct = if (tagIndex.size % 2 == 1) tagIndex.size
        else tagIndex.size + 1

         for (i in 0 until ct - 1) {
           if (status) {
                indexMap[tagIndex[i]] = tagMap.getValue(tag)
                status = false
            }
            else if (!status) {
                indexMap[tagIndex[i]] = tagMapClose.getValue(tag)
                status = true
            }
        }
                                                                        }
for (item in charList) {
        res += if (indexMap.keys.contains(charList.indexOf(item))) indexMap[charList.indexOf(item)]
        else item
    }
    return res
    }

但是在输出中我得到这个:
Lorem ipsum </i>dolor sit amet</i>, consectetur </b>adipiscing</b> elit.

因此,函数无法检查打开或关闭的标签,它只是只写关闭的标签,我该怎么办?

最佳答案

我强烈建议改用markdown解析器。这些可能更准确,并且比正则表达式受边缘情况的影响要小。
话虽如此,您可以使用正则表达式进行解析。但是,由于处理 token 的方式,您的方法失败了。您可以将 Markdown 标记分配给不同的统一标记(仅这是不必要的转换),然后将相同的标记分配给两个不同的结束标记。那和循环可能使所有标签最终以结束标签结束。
存储 token 不是一个坏主意,因此让我们从此开始。在**b以及*i之间创建连接。无需将***转换为bi-最后,解析将逐步进行转换,并将***content***首先转换为<b>*content*</b>,然后将其转换为<b><i>content</b></i>。在这种情况下,我通过正则表达式进行映射,以使其以后变得更容易:

val tokens = mapOf(
    "\\*\\*" to "b", "\\*" to "i", "~~" to "s"
)
正则表达式本身更复杂:
不应该匹配空的空格,应该忽略空格的空格,并且需要针对两种不同的类型进行匹配。
无论如何,我们有一个核心的正则表达式:
val core = "(?<!\* )(?=\S)(.+?[*]*)(?<=\S)(?<! \*)"
请注意,单独使用不能单独使用。第一组和最后一组是为了避免将*** something***解析为有效的,因为*也是内部的有效字符。
在这种情况下,我在示例中定义了var string: String,但是您当然可以用其他替换它。这只是为了可移植性。
var string = "***this*** **is** a ***test of* a markdown *regex* parsing system** that I really **hope *works* like it's supposed to**. " +
        "And an ** invalid one **, and not to forget ~~the broken regex~~ the perfect regex"

for ((token, html) in tokens) { // if you don't know, Map entries can be unpacked like tuples. The token is for an instance **, and html is b
    val modRegex = "$token$core$token".toRegex() // Construct the regex. This is why the format in the map is regex-style
    string = string.replace(modRegex, "<$html>$1</$html>")//And finally, we replace it. The String templates ensure the right match, `$1` is the first capture group to avoid losing content

}
为了演示,我还打印了string:

现在,正则表达式远非完美,尤其是在 Markdown 方面。首先,存在几种边缘情况和不正确的 Markdown 带来的不正确处理。您不能只是在周围放置随机 token 并将其解释为有效的 Markdown 。因此,放置不正确的 token 可能会导致不正确的处理和解析,这也是为什么我强烈建议使用markdown解析器而不是regex的原因。
尽管可以将其扩展到其他 token ,但不适用于链接。 ()[]需要围绕HTML移动组才能起作用,并且有两个相关的组。 ($1)[$2]-> <a href="$1">$2</a>,这再次忽略了URL上的替代文本。
无论如何,此答案中的代码仍然可以在正则表达式解析系统上为您提供帮助,即使这还远远不够完美。

关于kotlin - 功能答案不正确,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/53803839/

10-10 23:46