Qt - Regex过滤富文本字符串并替换子字符串

时间:2013-07-10 09:17:43

标签: regex qt richtext

我在这种格式中或多或少地拥有QString富文本格式:

<span background-color="red"><a name='item1'></a> property1 </span> + <span background-color="blue"><a name='item2'></a> property2 </span>

它可以有更多标签,但所有标签都具有相同的结构。此外,在每个标记之间,运算符将显示 - 这是一个应该代表计算的字符串。

我需要一个正则表达式来遍历字符串并提取item1item2,...;还有property1property2,...子字符串,这样我就可以检索一个我存储在其他地方的值。

然后,在检索这些values后,如果,例如,property1 = value1和property2 = value2,我需要创建另一个字符串,如:

value1 + value2

将评估此字符串以计算计算结果。

读取字符串的正则表达式是什么?

在复制的字符串中要替换的正则表达式是什么?

注意我不打算使用这些正则表达式解析 HTML 。我需要过滤的富文本字符串最多 上面标记的代码和结构。除了上面示例字符串中的标记之外,它不会有其他类型的标记,也不会有其他属性。它只能包含 more 相同标记结构的示例:span,包含带有 name 属性的锚标记和一些要显示的文本。

NOTE2 @Passerby在此问题的评论中发布了一个非常近似解决方案的链接。我忘记了关于我的目标的一个(希望很小)细节:我还需要捕捉span标签之间的任何内容作为字符串,而不是简单地检查char像@Passerby(非常好)建议。有什么想法吗?

NOTE3 我实际上仍然认为这与与重复标记的问题相同。虽然我过滤的字符串看起来像HTML,但它们实际上是富文本。它们将始终具有这种严格的结构/格式,因此RegEx完全适用于我需要做的事情。在我从一些用户那里得到一些很好的评论之后,即@Passerby,我决定采用它,这完全符合我的需要:

示例字符串:

<span background-color="red"><a name='item1'></a> property1 </span> + 300 * <span background-color="blue"><a name='item2'></a> property2 </span> + Math.sqrt(<span background-color="green"><a name='item3'></a> property3 </span>)

正则表达式:

/ <span.*?><a name='(.*?)'><\/a>\s*(.*?)\s*<\/span>(((.*?)?)(?=<)|) / g

输出:

MATCH 1 
1. [38-43] `item1` 
2. [50-59] `property1` 
3. [67-76] ` + 300 * ` 
4. [67-76] ` + 300 * ` 
5. [67-76] ` + 300 * ` 
MATCH 2 
1. [115-120] `item2` 
2. [127-136] `property2` 
3. [144-157] ` + Math.sqrt(` 
4. [144-157] ` + Math.sqrt(` 
5. [144-157] ` + Math.sqrt(` 
MATCH 3 
1. [197-202] `item3` 
2. [209-218] `property3` 
3. [226-226] (null, matches any position) 

2 个答案:

答案 0 :(得分:1)

这可能类似于:

QRegExp rx("^(?:\\<span background-color=\"red\"\\>\\<a name=')(\\w)(?:'\\>\\</a\\>)\s*(\\d+)\s*(?:\\</span\\>)\s*(\+)\s*(?:\\<span background-color=\"blue\"\\>\\<a name=')(\\w)(?'\\>\\</a\\>)\")\\s*(\\d+)\\s*\\</span\\>)$");

rx.IndexIn(myText);
qDebug() << rx.cap(1) << rx.cap(2) << rx.cap(3) << rx.cap(4) << rx.cap(5);
//will return item1 prop1 + item2 prop2

给定item将是一个单词,property将是一个数字。我在软件计算器中做了类似的事情。

诀窍是,从小位开始:

rx("\\<a name='\\w'\\>");

将捕获该项目,但最终捕获完整的行。然后继续下一步并继续它,直到你得到你想要它的整行。 正则表达式可能非常强大但也非常令人沮丧。

祝你好运

编辑:可以通过替换功能中的\ 1访问每个括号()。 (?:)括号未被捕获!所以:

QString text = "My Text";
text.replace("^My( Text)$","His\\1");
//will have returned: His Text

答案 1 :(得分:0)

我也不了解正则表达式。有了这种解析问题,我会使用这样的快速和(可能)脏解决方案:

QString str = "<span background-color='red'><a name='item1'></a> property1 </span> + <span background-color='blue'><a name='item2'></a> property2 </span>";
QStringList slist = str.split("<");

qDebug() << slist;

foreach (QString s, slist)
{
    if (s.startsWith("/a"))
    {
        qDebug() << "property:" << s.split(" ")[1];
    }
    else if (s.startsWith("a name"))
    {
        qDebug() << "item:" << s.split("'")[1];
    }
    else if (s.startsWith("/span>"))
    {
        QString op = s.mid(6).trimmed();
        if (op != "")
            qDebug() << "operator:" << op;
    }
}

输出是:

item: "item1" 
property: "property1" 
operator: "+" 
item: "item2" 
property: "property2"

当然,如果格式发生变化,这将会中断。但正则表达式也是如此。

如果格式更复杂,我会尝试将格式更改为有效的XML,然后使用Qt的XML类来解析数据。

如果你最终使用这种解决方案,我真的建议添加一些额外的有效性检查。