Files
utun2/tools/chatgui/src/message_links.cpp
T

40 lines
1.9 KiB
C++

#include "message_links.h"
#include <QRegularExpression>
#include <QUrl>
/* Отделить адрес от текста, сохраняя сбалансированные скобки внутри пути/query. */
QVector<MessageLink> messageLinks(const QString& text) {
static const QRegularExpression pattern(QStringLiteral(
"utun://[A-Za-z0-9+/]+={0,2}|(?i:https?://)[^\\s\\p{Z}\\p{Cc}<>\"'`«»“”‘’]+"));
QVector<MessageLink> links;
auto matches = pattern.globalMatch(text);
while (matches.hasNext()) {
const auto match = matches.next();
QString url = match.captured();
if (!url.startsWith(QStringLiteral("utun://"))) {
// Один подсчёт и один проход по хвосту: повторный count() на каждой скобке даёт O(n²).
qsizetype balance[3] = {};
for (const QChar ch : url) {
const int opening = QStringLiteral("([{").indexOf(ch);
const int closing = QStringLiteral(")]}").indexOf(ch);
if (opening >= 0) balance[opening]--;
if (closing >= 0) balance[closing]++;
}
auto end = url.size();
while (end > 0) {
const QChar last = url.at(end - 1);
const int closing = QStringLiteral(")]}").indexOf(last);
const bool unmatched = closing >= 0 && balance[closing] > 0;
if (!QStringLiteral(".,;:!?").contains(last) && !unmatched) break;
if (closing >= 0) balance[closing]--;
end--;
}
url.truncate(end);
const QUrl parsed(url, QUrl::StrictMode);
if (!parsed.isValid() || parsed.host().isEmpty()) continue;
}
links.append({(int)match.capturedStart(), (int)url.length(), url});
}
return links;
}