3 changed files with 44 additions and 1 deletions
@ -0,0 +1,28 @@
|
||||
#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://"))) { |
||||
while (!url.isEmpty()) { |
||||
const QChar last = url.back(); |
||||
const int closing = QStringLiteral(")]}").indexOf(last); |
||||
const bool unmatched = closing >= 0 && url.count(last) > url.count(QStringLiteral("([{").at(closing)); |
||||
if (!QStringLiteral(".,;:!?").contains(last) && !unmatched) break; |
||||
url.chop(1); |
||||
} |
||||
const QUrl parsed(url, QUrl::StrictMode); |
||||
if (!parsed.isValid() || parsed.host().isEmpty()) continue; |
||||
} |
||||
links.append({(int)match.capturedStart(), (int)url.length(), url}); |
||||
} |
||||
return links; |
||||
} |
||||
@ -0,0 +1,14 @@
|
||||
/* Ссылки в обычном тексте сообщения: границы UTF-16 и полный адрес для подсветки и нажатия.
|
||||
* Поддерживает utun:// и HTTP/HTTPS; внешняя пунктуация не входит в адрес.
|
||||
* Разбор не меняет сообщение и не открывает адреса. Некорректные URL остаются обычным текстом. */ |
||||
#pragma once |
||||
#include <QString> |
||||
#include <QVector> |
||||
|
||||
struct MessageLink { |
||||
int start; |
||||
int length; |
||||
QString url; |
||||
}; |
||||
|
||||
QVector<MessageLink> messageLinks(const QString& text); |
||||
Loading…
Reference in new issue