Revert "Use Perl-compatible regexes for RSS rules. Closes #6367."

This reverts commit 8d11af94f2.
This commit is contained in:
sledgehammer999 2017-04-04 03:25:27 +03:00
commit 444c2bdf19
No known key found for this signature in database
GPG key ID: 6E4A2D025B7CC9A2
6 changed files with 45 additions and 85 deletions

View file

@ -28,16 +28,14 @@
* Contact : chris@qbittorrent.org
*/
#include <QRegExp>
#include <QDebug>
#include <QDir>
#include <QRegExp>
#include <QRegularExpression>
#include <QString>
#include <QStringList>
#include "base/preferences.h"
#include "base/utils/fs.h"
#include "base/utils/string.h"
#include "rssfeed.h"
#include "rssarticle.h"
#include "rssdownloadrule.h"
@ -54,23 +52,23 @@ DownloadRule::DownloadRule()
bool DownloadRule::matches(const QString &articleTitle, const QString &expression) const
{
static QRegularExpression whitespace("\\s+");
static QRegExp whitespace("\\s+");
if (expression.isEmpty()) {
// A regex of the form "expr|" will always match, so do the same for wildcards
return true;
}
else if (m_useRegex) {
QRegularExpression reg(expression, QRegularExpression::CaseInsensitiveOption);
return reg.match(articleTitle).hasMatch();
QRegExp reg(expression, Qt::CaseInsensitive, QRegExp::RegExp);
return reg.indexIn(articleTitle) > -1;
}
else {
// Only match if every wildcard token (separated by spaces) is present in the article name.
// Order of wildcard tokens is unimportant (if order is important, they should have used *).
foreach (const QString &wildcard, expression.split(whitespace, QString::SplitBehavior::SkipEmptyParts)) {
QRegularExpression reg(Utils::String::wildcardToRegex(wildcard), QRegularExpression::CaseInsensitiveOption);
QRegExp reg(wildcard, Qt::CaseInsensitive, QRegExp::Wildcard);
if (!reg.match(articleTitle).hasMatch())
if (reg.indexIn(articleTitle) == -1)
return false;
}
}
@ -126,15 +124,14 @@ bool DownloadRule::matches(const QString &articleTitle) const
if (!m_episodeFilter.isEmpty()) {
qDebug() << "Checking episode filter:" << m_episodeFilter;
QRegularExpression f("(^\\d{1,4})x(.*;$)");
QRegularExpressionMatch matcher = f.match(m_episodeFilter);
bool matched = matcher.hasMatch();
QRegExp f("(^\\d{1,4})x(.*;$)");
int pos = f.indexIn(m_episodeFilter);
if (!matched)
if (pos < 0)
return false;
QString s = matcher.captured(1);
QStringList eps = matcher.captured(2).split(";");
QString s = f.cap(1);
QStringList eps = f.cap(2).split(";");
int sOurs = s.toInt();
foreach (QString ep, eps) {
@ -148,24 +145,22 @@ bool DownloadRule::matches(const QString &articleTitle) const
if (ep.indexOf('-') != -1) { // Range detected
QString partialPattern1 = "\\bs0?(\\d{1,4})[ -_\\.]?e(0?\\d{1,4})(?:\\D|\\b)";
QString partialPattern2 = "\\b(\\d{1,4})x(0?\\d{1,4})(?:\\D|\\b)";
QRegularExpression reg(partialPattern1, QRegularExpression::CaseInsensitiveOption);
QRegExp reg(partialPattern1, Qt::CaseInsensitive);
if (ep.endsWith('-')) { // Infinite range
int epOurs = ep.left(ep.size() - 1).toInt();
// Extract partial match from article and compare as digits
matcher = reg.match(articleTitle);
matched = matcher.hasMatch();
pos = reg.indexIn(articleTitle);
if (!matched) {
reg = QRegularExpression(partialPattern2, QRegularExpression::CaseInsensitiveOption);
matcher = reg.match(articleTitle);
matched = matcher.hasMatch();
if (pos == -1) {
reg = QRegExp(partialPattern2, Qt::CaseInsensitive);
pos = reg.indexIn(articleTitle);
}
if (matched) {
int sTheirs = matcher.captured(1).toInt();
int epTheirs = matcher.captured(2).toInt();
if (pos != -1) {
int sTheirs = reg.cap(1).toInt();
int epTheirs = reg.cap(2).toInt();
if (((sTheirs == sOurs) && (epTheirs >= epOurs)) || (sTheirs > sOurs)) {
qDebug() << "Matched episode:" << ep;
qDebug() << "Matched article:" << articleTitle;
@ -183,18 +178,16 @@ bool DownloadRule::matches(const QString &articleTitle) const
int epOursLast = range.last().toInt();
// Extract partial match from article and compare as digits
matcher = reg.match(articleTitle);
matched = matcher.hasMatch();
pos = reg.indexIn(articleTitle);
if (!matched) {
reg = QRegularExpression(partialPattern2, QRegularExpression::CaseInsensitiveOption);
matcher = reg.match(articleTitle);
matched = matcher.hasMatch();
if (pos == -1) {
reg = QRegExp(partialPattern2, Qt::CaseInsensitive);
pos = reg.indexIn(articleTitle);
}
if (matched) {
int sTheirs = matcher.captured(1).toInt();
int epTheirs = matcher.captured(2).toInt();
if (pos != -1) {
int sTheirs = reg.cap(1).toInt();
int epTheirs = reg.cap(2).toInt();
if ((sTheirs == sOurs) && ((epOursFirst <= epTheirs) && (epOursLast >= epTheirs))) {
qDebug() << "Matched episode:" << ep;
qDebug() << "Matched article:" << articleTitle;
@ -205,8 +198,8 @@ bool DownloadRule::matches(const QString &articleTitle) const
}
else { // Single number
QString expStr("\\b(?:s0?" + s + "[ -_\\.]?" + "e0?" + ep + "|" + s + "x" + "0?" + ep + ")(?:\\D|\\b)");
QRegularExpression reg(expStr, QRegularExpression::CaseInsensitiveOption);
if (reg.match(articleTitle).hasMatch()) {
QRegExp reg(expStr, Qt::CaseInsensitive);
if (reg.indexIn(articleTitle) != -1) {
qDebug() << "Matched episode:" << ep;
qDebug() << "Matched article:" << articleTitle;
return true;

View file

@ -31,12 +31,10 @@
#ifndef RSSDOWNLOADRULE_H
#define RSSDOWNLOADRULE_H
#include <QDateTime>
#include <QStringList>
#include <QVariantHash>
#include <QSharedPointer>
#include <QStringList>
class QRegularExpression;
#include <QDateTime>
namespace Rss
{

View file

@ -38,7 +38,6 @@
#ifdef QBT_USES_QT5
#include <QCollator>
#endif
#include <QRegExp>
#ifdef Q_OS_MAC
#include <QThreadStorage>
#endif
@ -239,13 +238,3 @@ QString Utils::String::toHtmlEscaped(const QString &str)
return rich;
#endif
}
// This is marked as internal in QRegExp.cpp, but is exported. The alternative would be to
// copy the code from QRegExp::wc2rx().
QString qt_regexp_toCanonical(const QString &pattern, QRegExp::PatternSyntax patternSyntax);
QString Utils::String::wildcardToRegex(const QString &pattern)
{
return qt_regexp_toCanonical(pattern, QRegExp::Wildcard);
}

View file

@ -51,8 +51,6 @@ namespace Utils
bool naturalCompareCaseSensitive(const QString &left, const QString &right);
bool naturalCompareCaseInsensitive(const QString &left, const QString &right);
QString wildcardToRegex(const QString &pattern);
}
}

View file

@ -28,15 +28,14 @@
* Contact : chris@qbittorrent.org
*/
#include <QCursor>
#include <QDebug>
#include <QFileDialog>
#include <QMessageBox>
#include <QFileDialog>
#include <QDebug>
#include <QMenu>
#include <QRegularExpression>
#include <QCursor>
#include "base/bittorrent/session.h"
#include "base/preferences.h"
#include "base/bittorrent/session.h"
#include "base/rss/rssdownloadrulelist.h"
#include "base/rss/rssmanager.h"
#include "base/rss/rssfolder.h"
@ -73,8 +72,8 @@ AutomatedRssDownloader::AutomatedRssDownloader(const QWeakPointer<Rss::Manager>
Q_ASSERT(ok);
m_ruleList = manager.toStrongRef()->downloadRules();
m_editableRuleList = new Rss::DownloadRuleList; // Read rule list from disk
m_episodeRegex = new QRegularExpression("^(^\\d{1,4}x(\\d{1,4}(-(\\d{1,4})?)?;){1,}){1,1}",
QRegularExpression::CaseInsensitiveOption);
m_episodeRegex = new QRegExp("^(^\\d{1,4}x(\\d{1,4}(-(\\d{1,4})?)?;){1,}){1,1}",
Qt::CaseInsensitive);
QString tip = "<p>" + tr("Matches articles based on episode filter.") + "</p><p><b>" + tr("Example: ")
+ "1x2;8-15;5;30-;</b>" + tr(" will match 2, 5, 8 through 15, 30 and onward episodes of season one", "example X will match") + "</p>";
tip += "<p>" + tr("Episode filter rules: ") + "</p><ul><li>" + tr("Season number is a mandatory non-zero value") + "</li>"
@ -672,7 +671,7 @@ void AutomatedRssDownloader::updateFieldsToolTips(bool regex)
{
QString tip;
if (regex) {
tip = "<p>" + tr("Regex mode: use Perl-compatible regular expressions") + "</p>";
tip = "<p>" + tr("Regex mode: use Perl-like regular expressions") + "</p>";
}
else {
tip = "<p>" + tr("Wildcard mode: you can use") + "<ul>"
@ -698,23 +697,17 @@ void AutomatedRssDownloader::updateFieldsToolTips(bool regex)
void AutomatedRssDownloader::updateMustLineValidity()
{
const QString text = ui->lineContains->text();
bool isRegex = ui->checkRegex->isChecked();
bool valid = true;
QString error;
if (!text.isEmpty()) {
QStringList tokens;
if (isRegex)
if (ui->checkRegex->isChecked())
tokens << text;
else
foreach (const QString &token, text.split("|"))
tokens << Utils::String::wildcardToRegex(token);
tokens << text.split("|");
foreach (const QString &token, tokens) {
QRegularExpression reg(token, QRegularExpression::CaseInsensitiveOption);
QRegExp reg(token, Qt::CaseInsensitive, ui->checkRegex->isChecked() ? QRegExp::RegExp : QRegExp::Wildcard);
if (!reg.isValid()) {
if (isRegex)
error = tr("Position %1: %2").arg(reg.patternErrorOffset()).arg(reg.errorString());
valid = false;
break;
}
@ -724,35 +717,27 @@ void AutomatedRssDownloader::updateMustLineValidity()
if (valid) {
ui->lineContains->setStyleSheet("");
ui->lbl_must_stat->setPixmap(QPixmap());
ui->lbl_must_stat->setToolTip(QLatin1String(""));
}
else {
ui->lineContains->setStyleSheet("QLineEdit { color: #ff0000; }");
ui->lbl_must_stat->setPixmap(GuiIconProvider::instance()->getIcon("task-attention").pixmap(16, 16));
ui->lbl_must_stat->setToolTip(error);
}
}
void AutomatedRssDownloader::updateMustNotLineValidity()
{
const QString text = ui->lineNotContains->text();
bool isRegex = ui->checkRegex->isChecked();
bool valid = true;
QString error;
if (!text.isEmpty()) {
QStringList tokens;
if (isRegex)
if (ui->checkRegex->isChecked())
tokens << text;
else
foreach (const QString &token, text.split("|"))
tokens << Utils::String::wildcardToRegex(token);
tokens << text.split("|");
foreach (const QString &token, tokens) {
QRegularExpression reg(token, QRegularExpression::CaseInsensitiveOption);
QRegExp reg(token, Qt::CaseInsensitive, ui->checkRegex->isChecked() ? QRegExp::RegExp : QRegExp::Wildcard);
if (!reg.isValid()) {
if (isRegex)
error = tr("Position %1: %2").arg(reg.patternErrorOffset()).arg(reg.errorString());
valid = false;
break;
}
@ -762,19 +747,17 @@ void AutomatedRssDownloader::updateMustNotLineValidity()
if (valid) {
ui->lineNotContains->setStyleSheet("");
ui->lbl_mustnot_stat->setPixmap(QPixmap());
ui->lbl_mustnot_stat->setToolTip(QLatin1String(""));
}
else {
ui->lineNotContains->setStyleSheet("QLineEdit { color: #ff0000; }");
ui->lbl_mustnot_stat->setPixmap(GuiIconProvider::instance()->getIcon("task-attention").pixmap(16, 16));
ui->lbl_mustnot_stat->setToolTip(error);
}
}
void AutomatedRssDownloader::updateEpisodeFilterValidity()
{
const QString text = ui->lineEFilter->text();
bool valid = text.isEmpty() || m_episodeRegex->match(text).hasMatch();
bool valid = text.isEmpty() || m_episodeRegex->indexIn(text) != -1;
if (valid) {
ui->lineEFilter->setStyleSheet("");

View file

@ -57,7 +57,6 @@ namespace Rss
QT_BEGIN_NAMESPACE
class QListWidgetItem;
class QRegularExpression;
QT_END_NAMESPACE
class AutomatedRssDownloader: public QDialog
@ -113,7 +112,7 @@ private:
QListWidgetItem *m_editedRule;
Rss::DownloadRuleList *m_ruleList;
Rss::DownloadRuleList *m_editableRuleList;
QRegularExpression *m_episodeRegex;
QRegExp *m_episodeRegex;
QShortcut *editHotkey;
QShortcut *deleteHotkey;
QSet<QPair<QString, QString >> m_treeListEntries;