QRegularExpression Example▲
Sélectionnez
/**
**************************************************************************
**
** Copyright (C) 2016 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Giuseppe D'Angelo <giuseppe.dangelo@kdab.com>
** Copyright (C) 2016 Samuel Gaist <samuel.gaist@edeltech.ch>
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the examples of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:BSD$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** BSD License Usage
** Alternatively, you may use this file under the terms of the BSD license
** as follows:
**
** "Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions are
** met:
** * Redistributions of source code must retain the above copyright
** notice, this list of conditions and the following disclaimer.
** * Redistributions in binary form must reproduce the above copyright
** notice, this list of conditions and the following disclaimer in
** the documentation and/or other materials provided with the
** distribution.
** * Neither the name of The Qt Company Ltd nor the names of its
** contributors may be used to endorse or promote products derived
** from this software without specific prior written permission.
**
**
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
**
** $QT_END_LICENSE$
**
***************************************************************************
*/
#include
"regularexpressiondialog.h"
#include <QApplication>
#include <QCheckBox>
#include <QComboBox>
#include <QLabel>
#include <QLineEdit>
#include <QMenu>
#include <QSpinBox>
#include <QPlainTextEdit>
#include <QTreeWidget>
#include <QAction>
#include <QClipboard>
#include <QContextMenuEvent>
#include <QHBoxLayout>
#include <QGridLayout>
#include <QFormLayout>
#include <QRegularExpression>
#include <QRegularExpressionMatch>
#include <QRegularExpressionMatchIterator>
Q_DECLARE_METATYPE(QRegularExpression::
MatchType)
static
QString rawStringLiteral(QString pattern)
{
pattern.prepend(QLatin1String("R
\"
RX("
));
pattern.append(QLatin1String(")RX
\"
"
));
return
pattern;
}
static
QString patternToCode(QString pattern)
{
pattern.replace(QLatin1String("
\\
"
), QLatin1String("
\\\\
"
));
pattern.replace(QLatin1String("
\"
"
), QLatin1String("
\\\"
"
));
pattern.prepend(QLatin1Char('"'
));
pattern.append(QLatin1Char('"'
));
return
pattern;
}
static
QString codeToPattern(QString code)
{
for
(int
i =
0
; i &
lt; code.size(); ++
i) {
if
(code.at(i) ==
QLatin1Char('
\\
'
))
code.remove(i, 1
);
}
if
(code.startsWith(QLatin1Char('"'
)) &
amp;&
amp; code.endsWith(QLatin1Char('"'
))) {
code.chop(1
);
code.remove(0
, 1
);
}
return
code;
}
class
PatternLineEdit : public
QLineEdit
{
Q_OBJECT
public
:
explicit
PatternLineEdit(QWidget *
parent =
nullptr
);
private
slots:
void
copyToCode();
void
pasteFromCode();
void
escapeSelection();
protected
:
void
contextMenuEvent(QContextMenuEvent *
event) override
;
private
:
QAction *
escapeSelectionAction;
QAction *
copyToCodeAction;
QAction *
pasteFromCodeAction;
}
;
PatternLineEdit::
PatternLineEdit(QWidget *
parent) :
QLineEdit(parent),
escapeSelectionAction(new
QAction(tr("Escape Selection"
), this
)),
copyToCodeAction(new
QAction(tr("Copy to Code"
), this
)),
pasteFromCodeAction(new
QAction(tr("Paste from Code"
), this
))
{
setClearButtonEnabled(true
);
connect(escapeSelectionAction, &
amp;QAction::
triggered, this
, &
amp;PatternLineEdit::
escapeSelection);
connect(copyToCodeAction, &
amp;QAction::
triggered, this
, &
amp;PatternLineEdit::
copyToCode);
connect(pasteFromCodeAction, &
amp;QAction::
triggered, this
, &
amp;PatternLineEdit::
pasteFromCode);
#if !QT_CONFIG(clipboard)
copyToCodeAction-&
gt;setEnabled(false
);
pasteFromCodeAction-&
gt;setEnabled(false
);
#endif
}
void
PatternLineEdit::
escapeSelection()
{
const
QString selection =
selectedText();
const
QString escapedSelection =
QRegularExpression::
escape(selection);
if
(escapedSelection !=
selection) {
QString t =
text();
t.replace(selectionStart(), selection.size(), escapedSelection);
setText(t);
}
}
void
PatternLineEdit::
copyToCode()
{
#if QT_CONFIG(clipboard)
QGuiApplication::
clipboard()-&
gt;setText(patternToCode(text()));
#endif
}
void
PatternLineEdit::
pasteFromCode()
{
#if QT_CONFIG(clipboard)
setText(codeToPattern(QGuiApplication::
clipboard()-&
gt;text()));
#endif
}
void
PatternLineEdit::
contextMenuEvent(QContextMenuEvent *
event)
{
QMenu *
menu =
createStandardContextMenu();
menu-&
gt;setAttribute(Qt::
WA_DeleteOnClose);
menu-&
gt;addSeparator();
escapeSelectionAction-&
gt;setEnabled(hasSelectedText());
menu-&
gt;addAction(escapeSelectionAction);
menu-&
gt;addSeparator();
menu-&
gt;addAction(copyToCodeAction);
menu-&
gt;addAction(pasteFromCodeAction);
menu-&
gt;popup(event-&
gt;globalPos());
}
class
DisplayLineEdit : public
QLineEdit
{
public
:
explicit
DisplayLineEdit(QWidget *
parent =
nullptr
);
}
;
DisplayLineEdit::
DisplayLineEdit(QWidget *
parent) : QLineEdit(parent)
{
setReadOnly(true
);
QPalette disabledPalette =
palette();
disabledPalette.setBrush(QPalette::
Base, disabledPalette.brush(QPalette::
Disabled, QPalette::
Base));
setPalette(disabledPalette);
#if QT_CONFIG(clipboard)
QAction *
copyAction =
new
QAction(this
);
copyAction-&
gt;setText(RegularExpressionDialog::
tr("Copy to clipboard"
));
copyAction-&
gt;setIcon(QIcon(QStringLiteral(":/images/copy.png"
)));
connect(copyAction, &
amp;QAction::
triggered, this
,
[this
] () {
QGuiApplication::
clipboard()-&
gt;setText(text()); }
);
addAction(copyAction, QLineEdit::
TrailingPosition);
#endif
}
RegularExpressionDialog::
RegularExpressionDialog(QWidget *
parent)
:
QDialog(parent)
{
setupUi();
setWindowTitle(tr("QRegularExpression Example"
));
connect(patternLineEdit, &
amp;QLineEdit::
textChanged, this
, &
amp;RegularExpressionDialog::
refresh);
connect(subjectTextEdit, &
amp;QPlainTextEdit::
textChanged, this
, &
amp;RegularExpressionDialog::
refresh);
connect(caseInsensitiveOptionCheckBox, &
amp;QCheckBox::
toggled, this
, &
amp;RegularExpressionDialog::
refresh);
connect(dotMatchesEverythingOptionCheckBox, &
amp;QCheckBox::
toggled, this
, &
amp;RegularExpressionDialog::
refresh);
connect(multilineOptionCheckBox, &
amp;QCheckBox::
toggled, this
, &
amp;RegularExpressionDialog::
refresh);
connect(extendedPatternSyntaxOptionCheckBox, &
amp;QCheckBox::
toggled, this
, &
amp;RegularExpressionDialog::
refresh);
connect(invertedGreedinessOptionCheckBox, &
amp;QCheckBox::
toggled, this
, &
amp;RegularExpressionDialog::
refresh);
connect(dontCaptureOptionCheckBox, &
amp;QCheckBox::
toggled, this
, &
amp;RegularExpressionDialog::
refresh);
connect(useUnicodePropertiesOptionCheckBox, &
amp;QCheckBox::
toggled, this
, &
amp;RegularExpressionDialog::
refresh);
connect(optimizeOnFirstUsageOptionCheckBox, &
amp;QCheckBox::
toggled, this
, &
amp;RegularExpressionDialog::
refresh);
connect(dontAutomaticallyOptimizeOptionCheckBox, &
amp;QCheckBox::
toggled, this
, &
amp;RegularExpressionDialog::
refresh);
connect(offsetSpinBox, QOverload&
lt;int
&
gt;::
of(&
amp;QSpinBox::
valueChanged),
this
, &
amp;RegularExpressionDialog::
refresh);
connect(matchTypeComboBox, QOverload&
lt;int
&
gt;::
of(&
amp;QComboBox::
currentIndexChanged),
this
, &
amp;RegularExpressionDialog::
refresh);
connect(anchoredMatchOptionCheckBox, &
amp;QCheckBox::
toggled, this
, &
amp;RegularExpressionDialog::
refresh);
connect(dontCheckSubjectStringMatchOptionCheckBox, &
amp;QCheckBox::
toggled, this
, &
amp;RegularExpressionDialog::
refresh);
patternLineEdit-&
gt;setText(tr("(
\\
+?
\\
d+)-(?<prefix>
\\
d+)-(?<number>
\\
w+)"
));
subjectTextEdit-&
gt;setPlainText(tr("My office number is +43-152-0123456, my mobile is 001-41-255512 instead."
));
refresh();
}
void
RegularExpressionDialog::
setResultUiEnabled(bool
enabled)
{
matchDetailsTreeWidget-&
gt;setEnabled(enabled);
namedGroupsTreeWidget-&
gt;setEnabled(enabled);
}
static
void
setTextColor(QWidget *
widget, const
QColor &
amp;color)
{
QPalette palette =
widget-&
gt;palette();
palette.setColor(QPalette::
Text, color);
widget-&
gt;setPalette(palette);
}
void
RegularExpressionDialog::
refresh()
{
setUpdatesEnabled(false
);
const
QString pattern =
patternLineEdit-&
gt;text();
const
QString text =
subjectTextEdit-&
gt;toPlainText();
offsetSpinBox-&
gt;setMaximum(qMax(0
, text.length() -
1
));
escapedPatternLineEdit-&
gt;setText(patternToCode(pattern));
rawStringLiteralLineEdit-&
gt;setText(rawStringLiteral(pattern));
setTextColor(patternLineEdit, subjectTextEdit-&
gt;palette().color(QPalette::
Text));
matchDetailsTreeWidget-&
gt;clear();
namedGroupsTreeWidget-&
gt;clear();
regexpStatusLabel-&
gt;setText(QString());
if
(pattern.isEmpty()) {
setResultUiEnabled(false
);
setUpdatesEnabled(true
);
return
;
}
QRegularExpression rx(pattern);
if
(!
rx.isValid()) {
setTextColor(patternLineEdit, Qt::
red);
regexpStatusLabel-&
gt;setText(tr("Invalid: syntax error at position %1 (%2)"
)
.arg(rx.patternErrorOffset())
.arg(rx.errorString()));
setResultUiEnabled(false
);
setUpdatesEnabled(true
);
return
;
}
setResultUiEnabled(true
);
QRegularExpression::
MatchType matchType =
matchTypeComboBox-&
gt;currentData().value&
lt;QRegularExpression::
MatchType&
gt;();
QRegularExpression::
PatternOptions patternOptions =
QRegularExpression::
NoPatternOption;
QRegularExpression::
MatchOptions matchOptions =
QRegularExpression::
NoMatchOption;
if
(anchoredMatchOptionCheckBox-&
gt;isChecked())
matchOptions |=
QRegularExpression::
AnchoredMatchOption;
if
(dontCheckSubjectStringMatchOptionCheckBox-&
gt;isChecked())
matchOptions |=
QRegularExpression::
DontCheckSubjectStringMatchOption;
if
(caseInsensitiveOptionCheckBox-&
gt;isChecked())
patternOptions |=
QRegularExpression::
CaseInsensitiveOption;
if
(dotMatchesEverythingOptionCheckBox-&
gt;isChecked())
patternOptions |=
QRegularExpression::
DotMatchesEverythingOption;
if
(multilineOptionCheckBox-&
gt;isChecked())
patternOptions |=
QRegularExpression::
MultilineOption;
if
(extendedPatternSyntaxOptionCheckBox-&
gt;isChecked())
patternOptions |=
QRegularExpression::
ExtendedPatternSyntaxOption;
if
(invertedGreedinessOptionCheckBox-&
gt;isChecked())
patternOptions |=
QRegularExpression::
InvertedGreedinessOption;
if
(dontCaptureOptionCheckBox-&
gt;isChecked())
patternOptions |=
QRegularExpression::
DontCaptureOption;
if
(useUnicodePropertiesOptionCheckBox-&
gt;isChecked())
patternOptions |=
QRegularExpression::
UseUnicodePropertiesOption;
if
(optimizeOnFirstUsageOptionCheckBox-&
gt;isChecked())
patternOptions |=
QRegularExpression::
OptimizeOnFirstUsageOption;
if
(dontAutomaticallyOptimizeOptionCheckBox-&
gt;isChecked())
patternOptions |=
QRegularExpression::
DontAutomaticallyOptimizeOption;
rx.setPatternOptions(patternOptions);
const
int
capturingGroupsCount =
rx.captureCount() +
1
;
QRegularExpressionMatchIterator iterator =
rx.globalMatch(text, offsetSpinBox-&
gt;value(), matchType, matchOptions);
int
i =
0
;
while
(iterator.hasNext()) {
QRegularExpressionMatch match =
iterator.next();
QTreeWidgetItem *
matchDetailTopItem =
new
QTreeWidgetItem(matchDetailsTreeWidget);
matchDetailTopItem-&
gt;setText(0
, QString::
number(i));
for
(int
captureGroupIndex =
0
; captureGroupIndex &
lt; capturingGroupsCount; ++
captureGroupIndex) {
QTreeWidgetItem *
matchDetailItem =
new
QTreeWidgetItem(matchDetailTopItem);
matchDetailItem-&
gt;setText(1
, QString::
number(captureGroupIndex));
matchDetailItem-&
gt;setText(2
, match.captured(captureGroupIndex));
}
++
i;
}
matchDetailsTreeWidget-&
gt;expandAll();
regexpStatusLabel-&
gt;setText(tr("Valid"
));
const
QStringList namedCaptureGroups =
rx.namedCaptureGroups();
for
(int
i =
0
; i &
lt; namedCaptureGroups.size(); ++
i) {
const
QString currentNamedCaptureGroup =
namedCaptureGroups.at(i);
QTreeWidgetItem *
namedGroupItem =
new
QTreeWidgetItem(namedGroupsTreeWidget);
namedGroupItem-&
gt;setText(0
, QString::
number(i));
namedGroupItem-&
gt;setText(1
, currentNamedCaptureGroup.isNull() ? tr("<no name>"
) : currentNamedCaptureGroup);
}
setUpdatesEnabled(true
);
}
void
RegularExpressionDialog::
setupUi()
{
QWidget *
leftHalfContainer =
setupLeftUi();
QFrame *
verticalSeparator =
new
QFrame;
verticalSeparator-&
gt;setFrameStyle(QFrame::
VLine |
QFrame::
Sunken);
QWidget *
rightHalfContainer =
setupRightUi();
QHBoxLayout *
mainLayout =
new
QHBoxLayout;
mainLayout-&
gt;addWidget(leftHalfContainer);
mainLayout-&
gt;addWidget(verticalSeparator);
mainLayout-&
gt;addWidget(rightHalfContainer);
setLayout(mainLayout);
}
QWidget *
RegularExpressionDialog::
setupLeftUi()
{
QWidget *
container =
new
QWidget;
QFormLayout *
layout =
new
QFormLayout(container);
layout-&
gt;setFieldGrowthPolicy(QFormLayout::
AllNonFixedFieldsGrow);
layout-&
gt;setMargin(0
);
QLabel *
regexpAndSubjectLabel =
new
QLabel(tr("<h3>Regular expression and text input</h3>"
));
layout-&
gt;addRow(regexpAndSubjectLabel);
patternLineEdit =
new
PatternLineEdit;
patternLineEdit-&
gt;setClearButtonEnabled(true
);
layout-&
gt;addRow(tr("&Pattern:"
), patternLineEdit);
rawStringLiteralLineEdit =
new
DisplayLineEdit;
layout-&
gt;addRow(tr("&Raw string literal:"
), rawStringLiteralLineEdit);
escapedPatternLineEdit =
new
DisplayLineEdit;
layout-&
gt;addRow(tr("&Escaped pattern:"
), escapedPatternLineEdit);
subjectTextEdit =
new
QPlainTextEdit;
layout-&
gt;addRow(tr("&Subject text:"
), subjectTextEdit);
caseInsensitiveOptionCheckBox =
new
QCheckBox(tr("Case insensitive (/i)"
));
dotMatchesEverythingOptionCheckBox =
new
QCheckBox(tr("Dot matches everything (/s)"
));
multilineOptionCheckBox =
new
QCheckBox(tr("Multiline (/m)"
));
extendedPatternSyntaxOptionCheckBox =
new
QCheckBox(tr("Extended pattern (/x)"
));
invertedGreedinessOptionCheckBox =
new
QCheckBox(tr("Inverted greediness"
));
dontCaptureOptionCheckBox =
new
QCheckBox(tr("Don't capture"
));
useUnicodePropertiesOptionCheckBox =
new
QCheckBox(tr("Use unicode properties (/u)"
));
optimizeOnFirstUsageOptionCheckBox =
new
QCheckBox(tr("Optimize on first usage"
));
dontAutomaticallyOptimizeOptionCheckBox =
new
QCheckBox(tr("Don't automatically optimize"
));
QGridLayout *
patternOptionsCheckBoxLayout =
new
QGridLayout;
int
gridRow =
0
;
patternOptionsCheckBoxLayout-&
gt;addWidget(caseInsensitiveOptionCheckBox, gridRow, 1
);
patternOptionsCheckBoxLayout-&
gt;addWidget(dotMatchesEverythingOptionCheckBox, gridRow, 2
);
++
gridRow;
patternOptionsCheckBoxLayout-&
gt;addWidget(multilineOptionCheckBox, gridRow, 1
);
patternOptionsCheckBoxLayout-&
gt;addWidget(extendedPatternSyntaxOptionCheckBox, gridRow, 2
);
++
gridRow;
patternOptionsCheckBoxLayout-&
gt;addWidget(invertedGreedinessOptionCheckBox, gridRow, 1
);
patternOptionsCheckBoxLayout-&
gt;addWidget(dontCaptureOptionCheckBox, gridRow, 2
);
++
gridRow;
patternOptionsCheckBoxLayout-&
gt;addWidget(useUnicodePropertiesOptionCheckBox, gridRow, 1
);
patternOptionsCheckBoxLayout-&
gt;addWidget(optimizeOnFirstUsageOptionCheckBox, gridRow, 2
);
++
gridRow;
patternOptionsCheckBoxLayout-&
gt;addWidget(dontAutomaticallyOptimizeOptionCheckBox, gridRow, 1
);
layout-&
gt;addRow(tr("Pattern options:"
), patternOptionsCheckBoxLayout);
offsetSpinBox =
new
QSpinBox;
layout-&
gt;addRow(tr("Match &offset:"
), offsetSpinBox);
matchTypeComboBox =
new
QComboBox;
matchTypeComboBox-&
gt;addItem(tr("Normal"
), QVariant::
fromValue(QRegularExpression::
NormalMatch));
matchTypeComboBox-&
gt;addItem(tr("Partial prefer complete"
), QVariant::
fromValue(QRegularExpression::
PartialPreferCompleteMatch));
matchTypeComboBox-&
gt;addItem(tr("Partial prefer first"
), QVariant::
fromValue(QRegularExpression::
PartialPreferFirstMatch));
matchTypeComboBox-&
gt;addItem(tr("No match"
), QVariant::
fromValue(QRegularExpression::
NoMatch));
layout-&
gt;addRow(tr("Match &type:"
), matchTypeComboBox);
dontCheckSubjectStringMatchOptionCheckBox =
new
QCheckBox(tr("Don't check subject string"
));
anchoredMatchOptionCheckBox =
new
QCheckBox(tr("Anchored match"
));
QGridLayout *
matchOptionsCheckBoxLayout =
new
QGridLayout;
matchOptionsCheckBoxLayout-&
gt;addWidget(dontCheckSubjectStringMatchOptionCheckBox, 0
, 0
);
matchOptionsCheckBoxLayout-&
gt;addWidget(anchoredMatchOptionCheckBox, 0
, 1
);
layout-&
gt;addRow(tr("Match options:"
), matchOptionsCheckBoxLayout);
return
container;
}
QWidget *
RegularExpressionDialog::
setupRightUi()
{
QWidget *
container =
new
QWidget;
QFormLayout *
layout =
new
QFormLayout(container);
layout-&
gt;setFieldGrowthPolicy(QFormLayout::
AllNonFixedFieldsGrow);
layout-&
gt;setMargin(0
);
QLabel *
matchInfoLabel =
new
QLabel(tr("<h3>Match information</h3>"
));
layout-&
gt;addRow(matchInfoLabel);
matchDetailsTreeWidget =
new
QTreeWidget;
matchDetailsTreeWidget-&
gt;setHeaderLabels(QStringList() &
lt;&
lt; tr("Match index"
) &
lt;&
lt; tr("Group index"
) &
lt;&
lt; tr("Captured string"
));
matchDetailsTreeWidget-&
gt;setSizeAdjustPolicy(QTreeWidget::
AdjustToContents);
layout-&
gt;addRow(tr("Match details:"
), matchDetailsTreeWidget);
QFrame *
horizontalSeparator =
new
QFrame;
horizontalSeparator-&
gt;setFrameStyle(QFrame::
HLine |
QFrame::
Sunken);
layout-&
gt;addRow(horizontalSeparator);
QLabel *
regexpInfoLabel =
new
QLabel(tr("<h3>Regular expression information</h3>"
));
layout-&
gt;addRow(regexpInfoLabel);
regexpStatusLabel =
new
QLabel(tr("Valid"
));
regexpStatusLabel-&
gt;setWordWrap(true
);
layout-&
gt;addRow(tr("Pattern status:"
), regexpStatusLabel);
namedGroupsTreeWidget =
new
QTreeWidget;
namedGroupsTreeWidget-&
gt;setHeaderLabels(QStringList() &
lt;&
lt; tr("Index"
) &
lt;&
lt; tr("Named group"
));
namedGroupsTreeWidget-&
gt;setSizeAdjustPolicy(QTreeWidget::
AdjustToContents);
namedGroupsTreeWidget-&
gt;setRootIsDecorated(false
);
layout-&
gt;addRow(tr("Named groups:"
), namedGroupsTreeWidget);
return
container;
}
#include
"regularexpressiondialog.moc"