bool QuickFindPattern::isLineMatchingBackward( const QString& line, int column ) const { int pos = 0; if ( ! active_ ) return false; QRegularExpressionMatchIterator matches = regexp_.globalMatch(line); QRegularExpressionMatch lastMatch; while ( matches.hasNext() ) { QRegularExpressionMatch nextMatch = matches.peekNext(); if ( column >= 0 && nextMatch.capturedEnd() >= column ) { break; } lastMatch = matches.next(); } if ( lastMatch.hasMatch() ) { lastMatchStart_ = lastMatch.capturedStart(); lastMatchEnd_ = lastMatch.capturedEnd() - 1; return true; } else { return false; } }
void HtmlParser::parse() { while(!_downloaded) { QThread::msleep(10); } _info->_status = UrlInfo::PARSING; emit processing(_info.data()); _info->_found = _content.contains(_text, Qt::CaseInsensitive); int start_offset = -1; QRegularExpression regExp("(?:https?|ftp)://(((((((((\\w|\\d)|\\055)|\\056)|\\046)|\\077)|\\043)|\\045)|\\057)|\\075)+"); while (true) { QRegularExpressionMatch match = regExp.match(_content, ++start_offset); if (!match.hasMatch()) break; start_offset = match.capturedStart(); int end_offset = match.capturedEnd(); _links << new HtmlParser(_content.mid(start_offset, end_offset), _text); } _content.clear(); if (_downloader) delete _downloader; _downloader = nullptr; _info->_status = UrlInfo::FINISHED; emit processing(_info.data()); }
QString TxtFileView::addBoldMarks(QString txtline) { int i=0; if(m_isRegEx) { QRegularExpressionMatch match; while( (match = m_stxtRe.match(txtline, i)).hasMatch() ) { txtline.insert(match.capturedEnd(),"</u></b>"); txtline.insert(match.capturedStart(),"<b><u>"); i=match.capturedEnd()+6+8; m_hits++; } } else { while ((i = txtline.indexOf(m_stxt, i, Qt::CaseInsensitive)) != -1) { txtline.insert(i+m_stxt.size(),"</u></b>"); txtline.insert(i,"<b><u>"); i+=m_stxt.size()+6+8; m_hits++; } } return txtline; }
void AndroidDevice::filterAndAddToTextEdit(const QString& line) { static const QRegularExpression re( "(?<date>[\\d-]+) *(?<time>[\\d:\\.]+) *(?<pid>\\d+) *(?<tid>\\d+) *(?<verbosity>[A-Z]) *(?<tag>.+):", QRegularExpression::InvertedGreedinessOption | QRegularExpression::DotMatchesEverythingOption ); bool filtersMatch = true; const QRegularExpressionMatch match = re.match(line); if (match.hasMatch()) { const QStringRef date = match.capturedRef("date"); const QStringRef time = match.capturedRef("time"); const QStringRef pid = match.capturedRef("pid"); const QStringRef tid = match.capturedRef("tid"); const QStringRef verbosity = match.capturedRef("verbosity"); const QStringRef tag = match.capturedRef("tag").trimmed(); const QStringRef text = line.midRef(match.capturedEnd("tag") + 1); const auto verbosityLevel = static_cast<VerbosityEnum>(Utils::verbosityCharacterToInt(verbosity.at(0).toLatin1())); checkFilters(filtersMatch, m_filtersValid, verbosityLevel, pid, tid, tag, text); if (filtersMatch) { const auto verbosityColorType = static_cast<ColorTheme::ColorType>(verbosityLevel); m_deviceWidget->addText(verbosityColorType, verbosity); m_deviceWidget->addText(ColorTheme::DateTime, date); m_deviceWidget->addText(ColorTheme::DateTime, time); m_deviceWidget->addText(ColorTheme::Pid, pid); m_deviceWidget->addText(ColorTheme::Tid, tid); m_deviceWidget->addText(ColorTheme::Tag, tag); m_deviceWidget->addText(verbosityColorType, text); m_deviceWidget->flushText(); } } else { qDebug() << "failed to parse" << line; checkFilters(filtersMatch, m_filtersValid); if (filtersMatch) { m_deviceWidget->addText(ColorTheme::VerbosityVerbose, QStringRef(&line)); m_deviceWidget->flushText(); } } m_deviceWidget->highlightFilterLineEdit(!m_filtersValid); }
bool QuickFindPattern::isLineMatching( const QString& line, int column ) const { if ( ! active_ ) return false; QRegularExpressionMatch match = regexp_.match( line, column ); if ( match.hasMatch() ) { lastMatchStart_ = match.capturedStart(); lastMatchEnd_ = match.capturedEnd() - 1; return true; } else { return false; } }
bool HRProcessor::test(const Element &, const QString &block) { //! No atomic grouping in python so we simulate it here for performance. //! The regex only matches what would be in the atomic group - the HR. //! Then check if we are at end of block or if next char is a newline. QRegularExpressionMatch m = this->SEARCH_RE.match(block); if ( m.hasMatch() && ( m.capturedEnd() == block.size() || block.at(m.capturedStart()+m.capturedLength()) == '\n' ) ) { //! Save match object on class instance so we can use it later. this->match = m; return true; } return false; }
bool SearchWorker::searchTxtLoop(QTextStream *intxt, QString searchtype, QString searchTerm, bool singleMatch, QString fullpath, QString displabel) { int matchcount=0; QString matchline = ""; QString firstmatchline = ""; //prepare fo RegEx bool enableRegEx = m_profile.getBoolOption(Profile::EnableRegEx); const QRegularExpression searchExpr(searchTerm, QRegularExpression::UseUnicodePropertiesOption); if(!searchExpr.isValid()) enableRegEx=false; while (!intxt->atEnd()) { if (m_cancelled.loadAcquire() == Cancelled) return false; QString linetxt = intxt->readLine(); int findpos=0; QRegularExpressionMatch matchR; //search for several occurences of search text in one line while ( (findpos = (enableRegEx ? (matchR = searchExpr.match(linetxt, findpos)).capturedStart() : linetxt.indexOf(searchTerm, findpos, Qt::CaseInsensitive))) != -1) { //prepate line for output if (findpos>10) matchline = "\u2026" + linetxt.mid(findpos-10,120); else matchline = linetxt.left(120); if(matchcount==0) firstmatchline=matchline; enableRegEx ? findpos=matchR.capturedEnd() : findpos+=searchTerm.size(); matchcount++; if(!singleMatch) { //found result //APPS only on single match if(searchtype != "APPS") emit matchFound(fullpath, searchtype, displabel, matchline, 0); } if (m_cancelled.loadAcquire() == Cancelled) return false; } } if( singleMatch && (matchcount >0) ) { //found result if(searchtype == "APPS") { displabel = prepareForApps(intxt); matchcount = (-1)*matchcount; if(displabel.size()>0) emit matchFound(fullpath, searchtype, displabel, firstmatchline, matchcount); } else emit matchFound(fullpath, searchtype, displabel, firstmatchline, matchcount); } return true; }
std::tuple<QString, QString> get_class_and_title(const QRegularExpressionMatch &match) { QString klass = match.captured(1).toLower(); QString title = match.captured(2); if ( match.capturedEnd(2) == -1 ) { //! no title was provided, use the capitalized classname as title //! e.g.: `!!! note` will render //! `<p class="admonition-title">Note</p>` title = pypp::capitalize(klass); } else if ( title.isEmpty() ) { //! an explicit blank title should not be rendered //! e.g.: `!!! warning ""` will *not* render `p` with a title //title = QString(); } return std::make_tuple(klass, title); }
bool run(const markdown::Element &parent, QStringList &blocks) { QString block = blocks.first(); blocks.pop_front(); QRegularExpressionMatch m = this->RE.match(block); if ( m.hasMatch() ) { QString before = block.left(m.capturedStart()); // All lines before direction QString after = block.mid(m.capturedEnd()); // All lines after direction if ( ! before.isEmpty() ) { // As the direction was not the first line of the block and the // lines before the direction must be parsed first, // recursively parse this lines as a block. std::shared_ptr<markdown::BlockParser> parser = this->parser.lock(); QStringList new_blocks = {before}; parser->parseBlocks(parent, new_blocks); } // Create direction QString body = m.captured(2); // background-image m = this->BGIMG_RE.match(body); if ( m.hasMatch() ) { markdown::Element img = markdown::createSubElement(parent, "img"); img->attrib["class"] = "background"; img->attrib["src"] = m.captured(1); img->attrib["alt"] = m.captured(2); } // TODO: other direction if ( ! m.hasMatch() ) { markdown::Element p = markdown::createSubElement(parent, "p"); p->attrib["class"] = "comment"; p->text = body; } if ( ! after.isEmpty() ) { // Insert remaining lines as first block for future parsing. blocks.insert(0, after); } return true; } else { // This should never happen, but just in case... qDebug() << "We've got a problem header: " << block; return false; } }
bool run(const Element &parent, QStringList &blocks) { Element sibling = this->lastChild(parent); QString block = blocks.front(); blocks.pop_front(); QRegularExpressionMatch m = this->RE.match(block); if ( m.hasMatch() ) { block = block.mid(m.capturedEnd()+1); //! removes the first line } QString theRest; std::tie(block, theRest) = this->detab(block); Element div; if ( m.hasMatch() ) { QString klass, title; std::tie(klass, title) = this->get_class_and_title(m); div = createSubElement(parent, "div"); div->set("class", QString("%1 %2").arg(this->classname()).arg(klass)); if ( ! title.isEmpty() ) { Element p = createSubElement(div, "p"); p->text = title; p->set("class", this->classname_title()); } } else { div = sibling; } std::shared_ptr<BlockParser> parser = this->parser.lock(); parser->parseChunk(div, block); if ( ! theRest.isEmpty() ) { //! This block contained unindented line(s) after the first indented //! line. Insert these lines as the first block of the master blocks //! list for future processing. blocks.insert(0, theRest); } return true; }
QStringList WorkbookParserPrivate::splitoutCellReference(QString expression) { QStringList result; QRegularExpression re = QRegularExpression(REGEX_CELL_REFERENCE_2); QRegularExpressionMatch match; int start, end = 0; QRegularExpressionMatchIterator it = re.globalMatch(expression); while (it.hasNext()) { match = it.next(); start = match.capturedStart(0); result.append(expression.mid(end, start - end)); // TODO replace cell references with actual contents of cell result.append(match.captured(0)); // TODO above end = match.capturedEnd(0); } if (end < expression.length()) result.append(expression.mid(end)); return result; }
void FlatTextarea::parseLinks() { // some code is duplicated in text.cpp! LinkRanges newLinks; QString text(toPlainText()); if (text.isEmpty()) { if (!_links.isEmpty()) { _links.clear(); emit linksChanged(); } return; } initLinkSets(); int32 len = text.size(); const QChar *start = text.unicode(), *end = start + text.size(); for (int32 offset = 0, matchOffset = offset; offset < len;) { QRegularExpressionMatch m = reDomain().match(text, matchOffset); if (!m.hasMatch()) break; int32 domainOffset = m.capturedStart(); QString protocol = m.captured(1).toLower(); QString topDomain = m.captured(3).toLower(); bool isProtocolValid = protocol.isEmpty() || validProtocols().contains(hashCrc32(protocol.constData(), protocol.size() * sizeof(QChar))); bool isTopDomainValid = !protocol.isEmpty() || validTopDomains().contains(hashCrc32(topDomain.constData(), topDomain.size() * sizeof(QChar))); if (protocol.isEmpty() && domainOffset > offset + 1 && *(start + domainOffset - 1) == QChar('@')) { QString forMailName = text.mid(offset, domainOffset - offset - 1); QRegularExpressionMatch mMailName = reMailName().match(forMailName); if (mMailName.hasMatch()) { offset = matchOffset = m.capturedEnd(); continue; } } if (!isProtocolValid || !isTopDomainValid) { offset = matchOffset = m.capturedEnd(); continue; } QStack<const QChar*> parenth; const QChar *domainEnd = start + m.capturedEnd(), *p = domainEnd; for (; p < end; ++p) { QChar ch(*p); if (chIsLinkEnd(ch)) break; // link finished if (chIsAlmostLinkEnd(ch)) { const QChar *endTest = p + 1; while (endTest < end && chIsAlmostLinkEnd(*endTest)) { ++endTest; } if (endTest >= end || chIsLinkEnd(*endTest)) { break; // link finished at p } p = endTest; ch = *p; } if (ch == '(' || ch == '[' || ch == '{' || ch == '<') { parenth.push(p); } else if (ch == ')' || ch == ']' || ch == '}' || ch == '>') { if (parenth.isEmpty()) break; const QChar *q = parenth.pop(), open(*q); if ((ch == ')' && open != '(') || (ch == ']' && open != '[') || (ch == '}' && open != '{') || (ch == '>' && open != '<')) { p = q; break; } } } if (p > domainEnd) { // check, that domain ended if (domainEnd->unicode() != '/' && domainEnd->unicode() != '?') { matchOffset = domainEnd - start; continue; } } newLinks.push_back(qMakePair(domainOffset - 1, p - start - domainOffset + 2)); offset = matchOffset = p - start; } if (newLinks != _links) { _links = newLinks; emit linksChanged(); } }
bool ZInstrument::loadSfz(const QString& s) { _program = 0; QFile f(s); if (!f.open(QIODevice::ReadOnly)) { qDebug("ZInstrument: cannot load %s", qPrintable(s)); return false; } QFileInfo fi(f); QString path = fi.absolutePath(); qint64 total = fi.size(); QString sample; SfzRegion r; SfzRegion g; // group r.init(path); g.init(path); bool groupMode = false; zerberus->setLoadProgress(0); while (!f.atEnd()) { QByteArray ba = f.readLine(); zerberus->setLoadProgress(((qreal)f.pos() * 100) / total); ba = ba.simplified(); if (ba.isEmpty() || ba.startsWith("//")) continue; if (zerberus->loadWasCanceled()) return false; if (ba.startsWith("<group>")) { if (!groupMode && !r.isEmpty()) addRegion(r); g.init(path); r.init(path); groupMode = true; ba = ba.mid(7); } else if (ba.startsWith("<region>")) { if (groupMode) { g = r; groupMode = false; } else { if (!r.isEmpty()) addRegion(r); r = g; // initialize next region with group values } ba = ba.mid(8); } QRegularExpression re("\\s?(\\w+)="); QRegularExpressionMatchIterator i = re.globalMatch(ba); while (i.hasNext()) { QRegularExpressionMatch match = i.next(); int si = match.capturedEnd(); int ei; if (i.hasNext()) { QRegularExpressionMatch nextMatch = i.peekNext(); ei = nextMatch.capturedStart(); } else ei = ba.size(); QString s = ba.mid(si, ei-si); r.readOp(match.captured(1), s); } } zerberus->setLoadProgress(100); if (!groupMode && !r.isEmpty()) addRegion(r); return true; }
void SourceEntryPrivate::parseData(const QString &data) { if (data.isEmpty()) return; QString tData = data.simplified(); // Check for nonvalid input if (tData.isEmpty() || tData == QChar('#')) { isValid = false; return; } // Check source enable state if (tData.at(0) == '#') { isEnabled = false; } // Handle multiple comment characters (hey, it happens!) while (tData.size() > 0 && tData.at(0) == '#') { // Remove starting '#' from tData tData = tData.remove(0, 1); tData = tData.trimmed(); } // Find any #'s past the start (these are comments) int idx = tData.indexOf('#'); if (idx > 0) { // Save the comment, then remove from tData comment = tData.right(tData.size() - idx - 1); tData.remove(idx, tData.size() - idx + 1); } const QRegularExpression rx("^([a-z\\-]+) *"); QRegularExpressionMatch match = rx.match(tData); // Parse type type = match.captured(1); const QSet<QString> types = { QLatin1String("rpm"), QLatin1String("rpm-src"), QLatin1String("deb"), QLatin1String("deb-src") }; if (!match.isValid() || !types.contains(type)) { isValid = false; return; } int start = match.capturedEnd(), end = tData.size(); // Parse architecture, see https://wiki.debian.org/Multiarch/HOWTO, Setting up sources if (tData[start] == '[') { QString metadata = tData.mid(start+1, tData.indexOf(']')-start-1); QStringList options = metadata.split(';'); for (const QString &option : options) { QStringList parts = option.split('='); if (parts.size() != 2) { isValid = false; return; } QString key = parts.at(0); if (key != QLatin1String("arch")) { isValid = false; return; } QString value = parts.at(1); architectures = value.split(','); } start+=metadata.size()+2; for (; tData[start] == ' '; ++start) {} } bool inString = false; bool done = false; for (int i = start; !done && i<end; ++i) { switch (tData[i].toLatin1()) { case ' ': if (!inString) { uri = tData.mid(start, i-start); start = i+1; done = true; } break; case '[': inString = true; break; case ']': inString = false; break; } } if (uri.isEmpty() || !done) { isValid = false; return; } QStringList pieces = tData.mid(start).split(' ', QString::SkipEmptyParts); if (pieces.isEmpty()) { // Invalid source entry isValid = false; return; } // Parse distro and (optionally) components dist = pieces.takeFirst(); components = pieces; }
QList<HTMLSpellCheck::MisspelledWord> HTMLSpellCheck::GetMisspelledWords(const QString &orig_text, int start_offset, int end_offset, const QString &search_regex, bool first_only, bool include_all_words) { SpellCheck *sc = SpellCheck::instance(); QString wordChars = sc->getWordChars(); bool in_tag = false; bool in_invalid_word = false; bool in_entity = false; int word_start = 0; QRegularExpression search(search_regex); QList<HTMLSpellCheck::MisspelledWord> misspellings; // Make sure text has beginning/end boundary markers for easier parsing QString text = QChar(' ') + orig_text + QChar(' '); // Ignore <style...</style> wherever it appears - change to spaces to keep text positions QRegularExpression style_re("<style[^<]*</style>"); QRegularExpressionMatchIterator i = style_re.globalMatch(text); while (i.hasNext()) { QRegularExpressionMatch match = i.next(); for (int pos = match.capturedStart(); pos < match.capturedEnd(); pos++) { text[pos] = QChar(' '); } } for (int i = 0; i < text.count(); i++) { QChar c = text.at(i); if (!in_tag) { QChar prev_c = i > 0 ? text.at(i - 1) : QChar(' '); QChar next_c = i < text.count() - 1 ? text.at(i + 1) : QChar(' '); if (IsBoundary(prev_c, c, next_c, wordChars)) { // If we're in an entity and we hit a boundary and it isn't // part of an entity then this is an invalid entity. if (in_entity && c != QChar(';')) { in_entity = false; } // Check possibilities that would mean this isn't a word worth considering. if (!in_invalid_word && !in_entity && word_start != -1 && (i - word_start) > 0) { QString word = Utility::Substring(word_start, i, text); if (!word.isEmpty() && word_start > start_offset && word_start <= end_offset) { if (include_all_words || !sc->spell(word)) { int cap_start = -1; if (!search_regex.isEmpty()) { QRegularExpressionMatch mo = search.match(word); cap_start = mo.capturedStart(); } if (search_regex.isEmpty() || cap_start != -1) { struct MisspelledWord misspelled_word; misspelled_word.text = word; // Make sure we account for the extra boundary added at the beginning misspelled_word.offset = word_start - 1; misspelled_word.length = i - word_start ; misspellings.append(misspelled_word); if (first_only) { return misspellings; } } } } } // We want to start the word with the character after the boundary. // If the next character is another boundary we'll just move forward one. word_start = i + 1; in_invalid_word = false; } else { // Ensure we're not dealing with some crazy run on text that isn't worth // considering as an actual word. if (!in_invalid_word && (i - word_start) > MAX_WORD_LENGTH) { in_invalid_word = true; } } if (c == QChar('&')) { in_entity = true; } if (c == QChar(';')) { in_entity = false; } } if (c == QChar('<')) { in_tag = true; word_start = -1; } if (in_tag && c == QChar('>')) { word_start = i + 1; in_tag = false; } } return misspellings; }
QString DocumentImporter::importScenario(const ImportParameters& _importParameters) const { // // Преобразовать заданный документ в QTextDocument // QTextDocument documentForImport; QFile documentFile(_importParameters.filePath); documentFile.open(QIODevice::ReadOnly); FormatReader* reader = FormatManager::createReader(&documentFile); reader->read(&documentFile, &documentForImport); // // Найти минимальный отступ слева для всех блоков // ЗАЧЕМ: во многих программах (Final Draft, Screeviner) сделано так, что поля // задаются за счёт оступов. Получается что и заглавие сцены и описание действия // имеют отступы. Так вот это и будет минимальным отступом, который не будем считать // int minLeftMargin = 1000; { QTextCursor cursor(&documentForImport); while (!cursor.atEnd()) { if (minLeftMargin > cursor.blockFormat().leftMargin()) { minLeftMargin = cursor.blockFormat().leftMargin(); } cursor.movePosition(QTextCursor::NextBlock); cursor.movePosition(QTextCursor::EndOfBlock); } } // // FIXME: много чего дублируется с ScenarioXml // // // Преобразовать его в xml-строку // QString scenarioXml; QTextCursor cursor(&documentForImport); QXmlStreamWriter writer(&scenarioXml); writer.writeStartDocument(); writer.writeStartElement(NODE_SCENARIO); writer.writeAttribute(ATTRIBUTE_VERSION, "1.0"); // // Для каждого блока текста определяем тип // // ... последний стиль блока ScenarioBlockStyle::Type lastBlockType = ScenarioBlockStyle::Undefined; // ... количество пустых строк int emptyLines = 0; do { cursor.movePosition(QTextCursor::EndOfBlock); // // Если в блоке есть текст // if (!cursor.block().text().simplified().isEmpty()) { // // ... определяем тип // const ScenarioBlockStyle::Type blockType = ::typeForTextCursor(cursor, lastBlockType, emptyLines, minLeftMargin, _importParameters.outline); const QString blockTypeName = ScenarioBlockStyle::typeName(blockType); QString blockText = cursor.block().text().simplified(); // // ... запишем данные в строку // writer.writeStartElement(blockTypeName); // // Если текущий тип "Время и место" и нужно удалить номер сцены, то делаем это // if (blockType == ScenarioBlockStyle::SceneHeading && _importParameters.removeScenesNumbers){ blockText = blockText.toUpper(); QRegularExpressionMatch match = START_FROM_NUMBER_CHECKER.match(blockText); if (match.hasMatch()) { blockText = blockText.mid(match.capturedEnd()); } } // // Выполняем корректировки // blockText = ::clearBlockText(blockType, blockText); // // Пишем текст // writer.writeStartElement(NODE_VALUE); writer.writeCDATA(blockText); writer.writeEndElement(); // // Пишем редакторские комментарии // if (_importParameters.saveReviewMarks) { const QTextBlock currentBlock = cursor.block(); if (!currentBlock.textFormats().isEmpty()) { writer.writeStartElement(NODE_REVIEW_GROUP); foreach (const QTextLayout::FormatRange& range, currentBlock.textFormats()) { // // Всё, кроме стандартного // if (range.format.boolProperty(Docx::IsForeground) || range.format.boolProperty(Docx::IsBackground) || range.format.boolProperty(Docx::IsHighlight) || range.format.boolProperty(Docx::IsComment)) { writer.writeStartElement(NODE_REVIEW); writer.writeAttribute(ATTRIBUTE_REVIEW_FROM, QString::number(range.start)); writer.writeAttribute(ATTRIBUTE_REVIEW_LENGTH, QString::number(range.length)); if (range.format.hasProperty(QTextFormat::ForegroundBrush)) { writer.writeAttribute(ATTRIBUTE_REVIEW_COLOR, range.format.foreground().color().name()); } if (range.format.hasProperty(QTextFormat::BackgroundBrush)) { writer.writeAttribute(ATTRIBUTE_REVIEW_BGCOLOR, range.format.background().color().name()); } writer.writeAttribute(ATTRIBUTE_REVIEW_IS_HIGHLIGHT, range.format.boolProperty(Docx::IsHighlight) ? "true" : "false"); // // ... комментарии // const QStringList comments = range.format.property(Docx::Comments).toStringList(); const QStringList authors = range.format.property(Docx::CommentsAuthors).toStringList(); const QStringList dates = range.format.property(Docx::CommentsDates).toStringList(); for (int commentIndex = 0; commentIndex < comments.size(); ++commentIndex) { writer.writeEmptyElement(NODE_REVIEW_COMMENT); writer.writeAttribute(ATTRIBUTE_REVIEW_COMMENT, comments.at(commentIndex)); writer.writeAttribute(ATTRIBUTE_REVIEW_AUTHOR, authors.at(commentIndex)); writer.writeAttribute(ATTRIBUTE_REVIEW_DATE, dates.at(commentIndex)); } // writer.writeEndElement(); } } writer.writeEndElement(); } } // // ... конец абзаца // writer.writeEndElement(); // // Запомним последний стиль блока и обнулим счётчик пустых строк // lastBlockType = blockType; emptyLines = 0; } // // Если в блоке нет текста, то увеличиваем счётчик пустых строк // else { ++emptyLines; } cursor.movePosition(QTextCursor::NextCharacter); } while (!cursor.atEnd());
Load::Load(QObject *parent) : QObject(parent), d_ptr(new LoadPrivate(this)) { Q_D(Load); ins = this; setObjectName("Load"); auto avProcess = [this](QNetworkReply *reply){ Q_D(Load); Task &task = d->queue.head(); int sharp = task.code.indexOf(QRegularExpression("[#_]")); switch (task.state){ case None: { QString i = task.code.mid(2, sharp - 2); QString p = sharp == -1 ? QString() : task.code.mid(sharp + 1); QString url("http://www.%1/video/av%2/"); url = url.arg(Utils::customUrl(Utils::Bilibili)).arg(i); if (!p.isEmpty()){ url += QString("index_%1.html").arg(p); } forward(QNetworkRequest(url), Page); break; } case Page: { d->model->clear(); QString api, id, video(reply->readAll()); int part = video.indexOf("<select"); if (part != -1 && sharp == -1){ QRegularExpression r("(?<=>).*?(?=</option>)"); QStringRef list(&video, part, video.indexOf("</select>", part) - part); QRegularExpressionMatchIterator i = r.globalMatch(list); api = "http://www.%1/video/%2/index_%3.html"; api = api.arg(Utils::customUrl(Utils::Bilibili)); while (i.hasNext()){ int index = d->model->rowCount() + 1; QStandardItem *item = new QStandardItem; item->setData(QUrl(api.arg(task.code).arg(index)), UrlRole); item->setData((task.code + "#%1").arg(index), StrRole); item->setData(Page, NxtRole); item->setData(Utils::decodeXml(i.next().captured()), Qt::EditRole); d->model->appendRow(item); } } if (d->model->rowCount() > 0){ emit stateChanged(task.state = Part); } else{ QRegularExpression r = QRegularExpression("cid[=\":]*\\d+", QRegularExpression::CaseInsensitiveOption); QRegularExpressionMatchIterator i = r.globalMatch(video); while (i.hasNext()){ QString m = i.next().captured(); m = QRegularExpression("\\d+").match(m).captured(); if (id.isEmpty()){ id = m; } else if (id != m){ id.clear(); break; } } if (!id.isEmpty()){ api = "http://comment.%1/%2.xml"; api = api.arg(Utils::customUrl(Utils::Bilibili)); forward(QNetworkRequest(api.arg(id)), File); } else{ emit stateChanged(203); qDebug() << "Fail to load danmaku, try biliApi"; dequeue(); } } break; } case File: { dumpDanmaku(reply->readAll(), Utils::Bilibili, false); emit stateChanged(task.state = None); dequeue(); break; } } }; auto avRegular = [](QString &code){ code.remove(QRegularExpression("/index(?=_\\d+\\.html)")); QRegularExpression r("a(v(\\d+([#_])?(\\d+)?)?)?"); r.setPatternOptions(QRegularExpression::CaseInsensitiveOption); return getRegular(r)(code); }; d->pool.append({ avRegular, 0, avProcess }); auto bbProcess = [this, avProcess](QNetworkReply *reply) { Q_D(Load); Task &task = d->queue.head(); switch (task.state) { case None: { QString i = task.code.mid(2); QString u = "http://www.%1/bangumi/i/%2/"; u = u.arg(Utils::customUrl(Utils::Bilibili)).arg(i); forward(QNetworkRequest(u), Page); break; } case Page: { d->model->clear(); QString page(reply->readAll()); QStringList list = page.split("<li data-index"); if (list.size() < 2) { emit stateChanged(task.state = None); dequeue(); break; } list.removeFirst(); QListIterator<QString> iter(list); iter.toBack(); while (iter.hasPrevious()) { QRegularExpression r; const QString &i = iter.previous(); r.setPattern("(?<=href=\")[^\"]+"); QString c = r.match(i).captured(); fixCode(c); r.setPattern("(?<=<span>).+(?=</span>)"); QString t = Utils::decodeXml(r.match(i).captured()); QStandardItem *item = new QStandardItem; item->setData(c, StrRole); item->setData(None, NxtRole); item->setData(t, Qt::EditRole); d->model->appendRow(item); } emit stateChanged(task.state = Part); } } }; auto bbRegular = [](QString &code) { code.replace(QRegularExpression("bangumi/i/(?=\\d+)"), "bb"); QRegularExpression r("b(b(\\d+)?)?"); r.setPatternOptions(QRegularExpression::CaseInsensitiveOption); return getRegular(r)(code); }; d->pool.append({ bbRegular, 0, bbProcess }); auto acProcess = [this](QNetworkReply *reply){ Q_D(Load); Task &task = d->queue.head(); int sharp = task.code.indexOf(QRegularExpression("[#_]")); switch (task.state){ case None: { QString i = task.code.mid(2, sharp - 2); QString p = sharp == -1 ? QString() : task.code.mid(sharp + 1); QString url("http://www.%1/v/ac%2"); url = url.arg(Utils::customUrl(Utils::AcFun)).arg(i); if (!p.isEmpty()){ url += QString("_%1").arg(p); } forward(QNetworkRequest(url), Page); break;; } case Page: { d->model->clear(); QRegularExpressionMatchIterator match = QRegularExpression("data-vid.*?</a>").globalMatch(reply->readAll()); while (match.hasNext()){ QStandardItem *item = new QStandardItem; QString part = match.next().captured(); QRegularExpression r; r.setPattern("(?<=>)[^>]+?(?=</a>)"); item->setData(Utils::decodeXml(r.match(part).captured()), Qt::EditRole); r.setPattern("(?<=data-vid=\").+?(?=\")"); QString next("http://static.comment.%1/V2/%2?pageSize=1000&pageNo=1"); next = next.arg(Utils::customUrl(Utils::AcFun)).arg(r.match(part).captured()); item->setData(next, UrlRole); item->setData((task.code + "#%1").arg(d->model->rowCount() + 1), StrRole); item->setData(File, NxtRole); d->model->appendRow(item); } if (sharp == -1 && d->model->rowCount() >= 2){ emit stateChanged(task.state = Part); } else{ int i = sharp == -1 ? 0 : task.code.mid(sharp + 1).toInt() - 1; if (i >= 0 && i < d->model->rowCount()){ forward(QNetworkRequest(d->model->item(i)->data(UrlRole).toUrl()), File); } else{ emit stateChanged(203); dequeue(); } } break; } case File: { QByteArray data = reply->readAll(); if (data != "[[],[],[]]"){ QNetworkRequest &request = task.request; QUrl url = request.url(); int page = QUrlQuery(url).queryItemValue("pageNo").toInt(); url.setQuery(QString()); request.setUrl(url); dumpDanmaku(data, Utils::AcFun, false); QUrlQuery query; query.addQueryItem("pageSize", "1000"); query.addQueryItem("pageNo", QString::number(page + 1)); url.setQuery(query); request.setUrl(url); forward(request, File); } else{ emit stateChanged(task.state = None); dequeue(); } break; } } }; auto acRegular = getRegular(QRegularExpression("a(c(\\d+([#_])?(\\d+)?)?)?", QRegularExpression::CaseInsensitiveOption)); d->pool.append({ acRegular, 0, acProcess }); auto abProcess = [this, acProcess](QNetworkReply *reply){ Q_D(Load); Task &task = d->queue.head(); int sharp = task.code.indexOf(QRegularExpression("[#_]")); switch (task.state){ case None: { QString url("http://www.%1/bangumi/video/page?bangumiId=%2&pageSize=30&pageNo=%3&order=2"); url = url.arg(Utils::customUrl(Utils::AcFun)).arg(task.code.mid(2, sharp - 2)); url = url.arg(sharp == -1 ? 1 : (task.code.mid(sharp + 1).toInt() - 1) / 30 + 1); forward(QNetworkRequest(url), Page); break; } case Page: { if (sharp != -1){ QJsonObject data = QJsonDocument::fromJson(reply->readAll()).object()["data"].toObject(); int i = task.code.mid(sharp + 1).toInt(); if (i > 0){ i = (i - 1) % 30; } else{ i = data["totalCount"].toInt(); if (i > 30){ task.code = task.code.left(sharp) + QString("#%1").arg(i); task.state = None; task.processer->process(nullptr); break; } } QJsonArray list = data["list"].toArray(); if (i < 0 || i >= list.size()){ emit stateChanged(203); dequeue(); break; } QString head("http://static.comment.%1/V2/%2?pageSize=1000&pageNo=1"); head = head.arg(Utils::customUrl(Utils::AcFun)); head = head.arg(list[i].toObject()["danmakuId"].toString()); forward(QNetworkRequest(head), File); break; } else{ d->model->clear(); } } case Part: { QJsonObject info = QJsonDocument::fromJson(reply->readAll()).object(); if (!info["success"].toBool() && d->model->rowCount() == 0){ emit stateChanged(info["status"].toInt()); dequeue(); } QJsonObject data = info["data"].toObject(); for (const QJsonValue &value : data["list"].toArray()){ QStandardItem *item = new QStandardItem; QJsonObject data = value.toObject(); item->setData(data["title"].toString(), Qt::EditRole); QString head("http://static.comment.%1/V2/%2?pageSize=1000&pageNo=1"); head = head.arg(Utils::customUrl(Utils::AcFun)).arg(data["danmakuId"].toString()); item->setData(head, UrlRole); item->setData((task.code + "#%1").arg(d->model->rowCount() + 1), StrRole); item->setData(File, NxtRole); d->model->appendRow(item); } if (task.state != Part){ emit stateChanged(task.state = Part); } if (data["pageNo"].toInt() < data["totalPage"].toInt()){ QUrl url = reply->request().url(); auto arg = QUrlQuery(url).queryItems(); for (auto &p : arg){ if (p.first == "pageNo"){ p.second = QString::number(p.second.toInt() + 1); break; } } QUrlQuery query; query.setQueryItems(arg); url.setQuery(query); d->remain.insert(d->manager.get(QNetworkRequest(url))); } break; } case File: { acProcess(reply); break; } } }; auto abRegular = getRegular(QRegularExpression("a(b(\\d+([#_])?(\\d+)?)?)?", QRegularExpression::CaseInsensitiveOption)); d->pool.append({ abRegular, 0, abProcess }); auto ccProcess = [this](QNetworkReply *reply){ Q_D(Load); Task &task = d->queue.head(); int sharp = task.code.indexOf(QRegularExpression("[#_]")); switch (task.state){ case None: { QString i = task.code.mid(2, sharp - 2); QString p = sharp == -1 ? QString() : task.code.mid(sharp + 1); QString url("http://www.%1/play/h%2/"); url = url.arg(Utils::customUrl(Utils::TuCao)).arg(i); if (!p.isEmpty()){ url += QString("#%1").arg(p); } forward(QNetworkRequest(url), Page); break; } case Page: { QString page = reply->readAll(); d->model->clear(); QRegularExpressionMatch m; QRegularExpression r("(?<=<li>)[^<]*(?=</li>)"); m = r.match(page, page.indexOf("<ul id=\"player_code\"")); QStringList list = m.captured().split("**"); m = r.match(page, m.capturedEnd()); QString code = m.captured(); for (const QString &iter : list){ QStandardItem *item = new QStandardItem; item->setData(iter.mid(iter.indexOf('|') + 1), Qt::EditRole); QString api("http://www.%1/index.php?m=mukio&c=index&a=init&playerID=%2"); api = api.arg(Utils::customUrl(Utils::TuCao)).arg((code + "-%1").arg(d->model->rowCount())); item->setData(api, UrlRole); item->setData((task.code + "#%1").arg(d->model->rowCount() + 1), StrRole); item->setData(File, NxtRole); d->model->appendRow(item); } if (sharp == -1 && d->model->rowCount() >= 2){ emit stateChanged(task.state = Part); } else{ int i = sharp == -1 ? 0 : task.code.mid(sharp + 1).toInt() - 1; if (i >= 0 && i < d->model->rowCount()){ forward(QNetworkRequest(d->model->item(i)->data(UrlRole).toUrl()), File); } else{ emit stateChanged(203); dequeue(); } } break; } case File: { dumpDanmaku(reply->readAll(), Utils::TuCao, false); emit stateChanged(task.state = None); dequeue(); break; } } }; auto ccRegular = [](QString &code){ code.replace(QRegularExpression("[Hh](?=\\d)"), "cc"); QRegularExpression r("c(c(\\d+([#_])?(\\d+)?)?)?"); r.setPatternOptions(QRegularExpression::CaseInsensitiveOption); return getRegular(r)(code); }; d->pool.append({ ccRegular, 0, ccProcess }); d->pool.append(Proc()); Proc *directProc = &d->pool.last(); directProc->process = [this](QNetworkReply *reply){ Q_D(Load); Task &task = d->queue.head(); switch (task.state){ case None: { QUrl url = QUrl::fromUserInput(task.code); task.request.setUrl(url); task.state = File; forward(); break; } case File: { Record load; QUrl url = reply->url(); QByteArray data(reply->readAll()); load.source = url.url(); load.access = url.isLocalFile() ? url.toLocalFile() : load.source; load.string = QFileInfo(task.code).fileName(); load.delay = task.delay; QString head = Utils::decodeTxt(data.left(512)); if (head.startsWith("[Script Info]")){ load.danmaku = Parse::parseComment(data, Utils::ASS); } else if (!head.startsWith("<?xml")){ load.danmaku = Parse::parseComment(data, Utils::AcFun); } else if (head.indexOf("<packet>") != -1){ load.danmaku = Parse::parseComment(data, Utils::Niconico); } else if (head.indexOf("<i>") != -1){ load.danmaku = Parse::parseComment(data, Utils::Bilibili); QString i = QRegularExpression("(?<=<chatid>)\\d+(?=</chatid>)").match(head).captured(); if (!i.isEmpty()){ load.source = "http://comment.%1/%2.xml"; load.source = load.source.arg(Utils::customUrl(Utils::Bilibili)).arg(i); } } else if (head.indexOf("<c>") != -1){ load.danmaku = Parse::parseComment(data, Utils::AcfunLocalizer); } if (load.delay != 0){ for (Comment &c : load.danmaku){ c.time += load.delay; } } Danmaku::instance()->appendToPool(&load); emit stateChanged(task.state = None); dequeue(); break; } } }; directProc->priority = -100; directProc->regular = [this, directProc](QString &code){ if (code.startsWith("full?") || code.startsWith("hist?")){ code.clear(); return false; } QUrl u = QUrl::fromUserInput(code); if (!u.host().isEmpty() && !u.path().isEmpty()){ return true; } if (QFileInfo(code).exists()){ return true; } code.clear(); return false; }; auto fullBiProcess = [this](QNetworkReply *reply){ Q_D(Load); Task &task = d->queue.head(); switch (task.state) { case None: { emit progressChanged(0); QString api("http://comment.%1/rolldate,%2"); api = api.arg(Utils::customUrl(Utils::Bilibili)); task.code = QUrlQuery(task.code.mid(5)).queryItemValue("source"); forward(QNetworkRequest(api.arg(QFileInfo(task.code).baseName())), Page); break; } case Page: { QByteArray data = reply->readAll(); QJsonArray date = QJsonDocument::fromJson(data).array(); if (date.isEmpty()) { emit stateChanged(203); dequeue(); break; } QJsonObject head = date.first().toObject(); QString url("http://comment.%1/dmroll,%2,%3"); url = url.arg(Utils::customUrl(Utils::Bilibili)); url = url.arg(head["timestamp"].toVariant().toInt()); url = url.arg(QFileInfo(task.code).baseName()); QNetworkRequest request(url); request.setAttribute(QNetworkRequest::User, data); forward(request, Code); break; } case Code: { QByteArray data = task.request.attribute(QNetworkRequest::User).toByteArray(); QJsonArray date = QJsonDocument::fromJson(data).array(); QMap<int, int> count; for (auto iter : date) { QJsonObject item = iter.toObject(); count[item["timestamp"].toVariant().toInt()] += item["new"].toVariant().toInt(); } data = reply->readAll(); if (count.size() >= 2) { int max = QRegularExpression("(?<=\\<max_count\\>).+(?=\\</max_count\\>)").match(data).captured().toInt(); int now = 0; auto getHistory = [d, &count, &task](int date) { QString url("http://comment.%1/dmroll,%2,%3"); url = url.arg(Utils::customUrl(Utils::Bilibili)); url = url.arg(date); url = url.arg(QFileInfo(task.code).baseName()); return d->manager.get(QNetworkRequest(url)); }; for (auto iter = count.begin() + 1;; ++iter) { now += iter.value(); if (iter + 1 == count.end()) { d->remain += getHistory(iter.key()); break; } else if (now + (iter + 1).value() > max) { d->remain += getHistory(iter.key()); now = 0; } } auto pool = QSharedPointer<QVector<Parse::ResultDelegate>>::create(); pool->append(Parse::parseComment(data, Utils::Bilibili)); double total = d->remain.size() + 2; for (QNetworkReply *iter : d->remain) { connect(iter, &QNetworkReply::finished, [=, &task]() { QByteArray data = iter->readAll(); pool->append(Parse::parseComment(data, Utils::Bilibili)); switch (iter->error()) { case QNetworkReply::NoError: emit progressChanged((total - d->remain.size()) / total); case QNetworkReply::OperationCanceledError: if (d->remain.isEmpty() && !pool->empty()) { Record load; load.full = true; for (auto &iter : *pool) { load.danmaku.append(iter); } load.source = task.code; Danmaku::instance()->appendToPool(&load); emit stateChanged(task.state = None); dequeue(); } default: break; } }); } emit progressChanged(2 / total); emit stateChanged(task.state = File); break; } else { emit progressChanged(1); dumpDanmaku(data, Utils::Bilibili, true); emit stateChanged(task.state = None); dequeue(); break; } } } }; auto fullBiRegular = QRegularExpression("^full\\?source=http://comment\\.bilibili\\.com/\\d+\\.xml$"); fullBiRegular.setPatternOptions(QRegularExpression::CaseInsensitiveOption); d->pool.append({ getRegular(fullBiRegular), 100, fullBiProcess }); auto histBiProcess = [this](QNetworkReply *reply){ Q_D(Load); Task &task = d->queue.head(); switch (task.state){ case None: { QUrlQuery query(task.code.mid(5)); task.code = query.queryItemValue("source"); QString cid = QFileInfo(task.code).baseName(); QString dat = query.queryItemValue("date"); QString url; QNetworkRequest request; if (dat != "0" && dat.toUInt() != QDateTime(QDate::currentDate()).toTime_t()){ url = QString("http://comment.%1/dmroll,%2,%3"); url = url.arg(Utils::customUrl(Utils::Bilibili)); url = url.arg(dat).arg(cid); int limit = QDateTime(QDateTime::fromTime_t(dat.toInt()).date().addDays(1)).toTime_t(); request.setAttribute(QNetworkRequest::User, limit); } else{ url = QString("http://comment.%1/%2.xml").arg(Utils::customUrl(Utils::Bilibili)); url = url.arg(cid); } request.setUrl(url); forward(request, File); break; } case File: { Record load; load.danmaku = Parse::parseComment(reply->readAll(), Utils::Bilibili); load.source = task.code; for (Record &iter : Danmaku::instance()->getPool()){ if (iter.source == load.source){ iter.full = false; iter.danmaku.clear(); iter.limit = 1; break; } } load.limit = task.request.attribute(QNetworkRequest::User).toInt(); Danmaku::instance()->appendToPool(&load); emit stateChanged(task.state = None); dequeue(); break; } } }; auto histBiRegular = QRegularExpression("^hist\\?source=http://comment\\.bilibili\\.com/\\d+\\.xml&date=\\d+$"); histBiRegular.setPatternOptions(QRegularExpression::CaseInsensitiveOption); d->pool.append({ getRegular(histBiRegular), 100, histBiProcess }); connect(this, &Load::stateChanged, [this](int code){ switch (code){ case None: case Page: case Part: case Code: case File: break; default: { Q_D(Load); if (!d->tryNext()){ emit errorOccured(code); } break; } } }); }
int main() { { //! [0] QRegularExpression re("a pattern"); //! [0] } { //! [1] QRegularExpression re; re.setPattern("another pattern"); //! [1] } { //! [2] // matches two digits followed by a space and a word QRegularExpression re("\\d\\d \\w+"); // matches a backslash QRegularExpression re2("\\\\"); //! [2] } { //! [3] QRegularExpression re("a third pattern"); QString pattern = re.pattern(); // pattern == "a third pattern" //! [3] } { //! [4] // matches "Qt rocks", but also "QT rocks", "QT ROCKS", "qT rOcKs", etc. QRegularExpression re("Qt rocks", QRegularExpression::CaseInsensitiveOption); //! [4] } { //! [5] QRegularExpression re("^\\d+$"); re.setPatternOptions(QRegularExpression::MultilineOption); // re matches any line in the subject string that contains only digits (but at least one) //! [5] } { //! [6] QRegularExpression re = QRegularExpression("^two.*words$", QRegularExpression::MultilineOption | QRegularExpression::DotMatchesEverythingOption); QRegularExpression::PatternOptions options = re.patternOptions(); // options == QRegularExpression::MultilineOption | QRegularExpression::DotMatchesEverythingOption //! [6] } { //! [7] // match two digits followed by a space and a word QRegularExpression re("\\d\\d \\w+"); QRegularExpressionMatch match = re.match("abc123 def"); bool hasMatch = match.hasMatch(); // true //! [7] } { //! [8] QRegularExpression re("\\d\\d \\w+"); QRegularExpressionMatch match = re.match("abc123 def"); if (match.hasMatch()) { QString matched = match.captured(0); // matched == "23 def" // ... } //! [8] } { //! [9] QRegularExpression re("\\d\\d \\w+"); QRegularExpressionMatch match = re.match("12 abc 45 def", 1); if (match.hasMatch()) { QString matched = match.captured(0); // matched == "45 def" // ... } //! [9] } { //! [10] QRegularExpression re("^(\\d\\d)/(\\d\\d)/(\\d\\d\\d\\d)$"); QRegularExpressionMatch match = re.match("08/12/1985"); if (match.hasMatch()) { QString day = match.captured(1); // day == "08" QString month = match.captured(2); // month == "12" QString year = match.captured(3); // year == "1985" // ... } //! [10] } { //! [11] QRegularExpression re("abc(\\d+)def"); QRegularExpressionMatch match = re.match("XYZabc123defXYZ"); if (match.hasMatch()) { int startOffset = match.capturedStart(1); // startOffset == 6 int endOffset = match.capturedEnd(1); // endOffset == 9 // ... } //! [11] } { //! [12] QRegularExpression re("^(?<date>\\d\\d)/(?<month>\\d\\d)/(?<year>\\d\\d\\d\\d)$"); QRegularExpressionMatch match = re.match("08/12/1985"); if (match.hasMatch()) { QString date = match.captured("date"); // date == "08" QString month = match.captured("month"); // month == "12" QString year = match.captured("year"); // year == 1985 } //! [12] } { //! [13] QRegularExpression re("(\\w+)"); QRegularExpressionMatchIterator i = re.globalMatch("the quick fox"); //! [13] //! [14] QStringList words; while (i.hasNext()) { QRegularExpressionMatch match = i.next(); QString word = match.captured(1); words << word; } // words contains "the", "quick", "fox" //! [14] } { //! [15] QString pattern("^(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec) \\d\\d?, \\d\\d\\d\\d$"); QRegularExpression re(pattern); QString input("Jan 21,"); QRegularExpressionMatch match = re.match(input, 0, QRegularExpression::PartialPreferCompleteMatch); bool hasMatch = match.hasMatch(); // false bool hasPartialMatch = match.hasPartialMatch(); // true //! [15] } { QString pattern("^(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec) \\d\\d?, \\d\\d\\d\\d$"); QRegularExpression re(pattern); //! [16] QString input("Dec 8, 1985"); QRegularExpressionMatch match = re.match(input, 0, QRegularExpression::PartialPreferCompleteMatch); bool hasMatch = match.hasMatch(); // true bool hasPartialMatch = match.hasPartialMatch(); // false //! [16] } { //! [17] QRegularExpression re("abc\\w+X|def"); QRegularExpressionMatch match = re.match("abcdef", 0, QRegularExpression::PartialPreferCompleteMatch); bool hasMatch = match.hasMatch(); // true bool hasPartialMatch = match.hasPartialMatch(); // false QString captured = match.captured(0); // captured == "def" //! [17] } { //! [18] QRegularExpression re("abc\\w+X|defY"); QRegularExpressionMatch match = re.match("abcdef", 0, QRegularExpression::PartialPreferCompleteMatch); bool hasMatch = match.hasMatch(); // false bool hasPartialMatch = match.hasPartialMatch(); // true QString captured = match.captured(0); // captured == "abcdef" //! [18] } { //! [19] QRegularExpression re("abc|ab"); QRegularExpressionMatch match = re.match("ab", 0, QRegularExpression::PartialPreferFirstMatch); bool hasMatch = match.hasMatch(); // false bool hasPartialMatch = match.hasPartialMatch(); // true //! [19] } { //! [20] QRegularExpression re("abc(def)?"); QRegularExpressionMatch match = re.match("abc", 0, QRegularExpression::PartialPreferFirstMatch); bool hasMatch = match.hasMatch(); // false bool hasPartialMatch = match.hasPartialMatch(); // true //! [20] } { //! [21] QRegularExpression re("(abc)*"); QRegularExpressionMatch match = re.match("abc", 0, QRegularExpression::PartialPreferFirstMatch); bool hasMatch = match.hasMatch(); // false bool hasPartialMatch = match.hasPartialMatch(); // true //! [21] } { //! [22] QRegularExpression invalidRe("(unmatched|parenthesis"); bool isValid = invalidRe.isValid(); // false //! [22] } { //! [23] QRegularExpression invalidRe("(unmatched|parenthesis"); if (!invalidRe.isValid()) { QString errorString = invalidRe.errorString(); // errorString == "missing )" int errorOffset = invalidRe.patternErrorOffset(); // errorOffset == 22 // ... } //! [23] } { //! [24] QRegularExpression re("^this pattern must match exactly$"); //! [24] } { //! [25] QString p("a .*|pattern"); QRegularExpression re("\\A(?:" + p + ")\\z"); // re matches exactly the pattern string p //! [25] } { //! [26] QString escaped = QRegularExpression::escape("a(x) = f(x) + g(x)"); // escaped == "a\\(x\\)\\ \\=\\ f\\(x\\)\\ \\+\\ g\\(x\\)" //! [26] } { QString name; QString nickname; //! [27] QString pattern = "(" + QRegularExpression::escape(name) + "|" + QRegularExpression::escape(nickname) + ")"; QRegularExpression re(pattern); //! [27] } { QString string; QRegularExpression re; //! [28] QRegularExpressionMatch match = re.match(string); for (int i = 0; i <= match.lastCapturedIndex(); ++i) { QString captured = match.captured(i); // ... } //! [28] } { //! [29] QRegularExpression re("(\\d\\d) (?<name>\\w+)"); QRegularExpressionMatch match = re.match("23 Jordan"); if (match.hasMatch()) { QString number = match.captured(1); // first == "23" QString name = match.captured("name"); // name == "Jordan" } //! [29] } { //! [30] // extracts the words QRegularExpression re("(\\w+)"); QString subject("the quick fox"); QRegularExpressionMatchIterator i = re.globalMatch(subject); while (i.hasNext()) { QRegularExpressionMatch match = i.next(); // ... } //! [30] } }
void MarkupHighlighter::highlightBlock(const QString &text) { if (FORMATTING.empty()){ qWarning() << "Not given any formatting, so not highlighting."; return; } if (text.isEmpty()) return; int start=0, end=0, highlightLength = 0; QRegularExpression re; QTextCharFormat textFormat; for (QString exp : TOKENS.keys()){ setCurrentBlockState(0); start = 0, end = 0; re = QRegularExpression(exp); if (!re.isValid()){ QString message = "Invalid regular expression \"" + re.pattern() + "\" :" + re.errorString(); qFatal("%s", message.toStdString().data()); return; } if (previousBlockState() != 1) start = re.match(text).capturedStart(); while (start >= 0){ QRegularExpressionMatch match = re.match(text, start); end = match.capturedEnd(); if (end == -1 || (end == start && end != 0)){ setCurrentBlockState(1); highlightLength = text.length(); } else { highlightLength = match.capturedLength(); } QTextCharFormat baseFormat = currentBlock().blockFormat().toCharFormat(); MarkupHighlighter::MarkupToken tok = TOKENS[exp]; if (!FORMATTING.contains(tok)){ qWarning() << "Could not find" << tok; break; } const StyleProxy *styleProxy = FORMATTING[tok]; textFormat = styleProxy->toFormat(baseFormat); setFormat(start, highlightLength, textFormat); qDebug() << "highlightBlock"; qDebug() << "Formatting" << "token" << tok << "with regex=" << exp << ", string=" << text.mid(start, highlightLength) << "\n" << " Bold?" << textFormat.font().bold() << "\n" << " Italic?" << textFormat.font().italic() << "\n" << " Size:" << textFormat.font().pointSize() << "\n" << " Background:" << textFormat.background().color(); start = re.match(text, end).capturedStart(); // This should not be 0 again. If it is, that means our search has // come up empty. if (start == 0) start = -1; } } }
bool ZInstrument::loadSfz(const QString& s) { _program = 0; QFileInfo fi(s); QString path = fi.absolutePath(); QStringList fileContents = readFile(s); if (fileContents.empty()) { return false; } SfzControl c; c.init(); c.defines.clear(); for (int i = 0;i < 128; i++) c.set_cc[i] = -1; int idx = 0; bool inBlockComment = false; // preprocessor while(idx < fileContents.size()) { QRegularExpression findWithSpaces("\"(.+)\""); QRegularExpression comment("//.*$"); QRegularExpression trailingSpacesOrTab("^[\\s\\t]*"); QRegularExpressionMatch foundWithSpaces; QString curLine = fileContents[idx]; QString curLineCopy = curLine; bool nextIsImportant = false; int idxBlockComment = 0; int from = 0; for (QChar chr : curLineCopy) { bool terminated = false; if (nextIsImportant) { nextIsImportant = false; if (inBlockComment && chr == '/') { // found block end inBlockComment = false; terminated = true; curLine.remove(from, idxBlockComment - from + 1); idxBlockComment = from - 1; } else if (!inBlockComment && chr == '*') { // found block start inBlockComment = true; terminated = true; from = idxBlockComment - 1; } } if (!terminated && inBlockComment && chr == '*') nextIsImportant = true; else if (!terminated && !inBlockComment && chr == '/') nextIsImportant = true; idxBlockComment++; } if (inBlockComment) curLine.remove(from, curLine.size() - from); curLine = curLine.remove(comment); curLine.remove(trailingSpacesOrTab); fileContents[idx] = curLine; if (curLine.startsWith("#define")) { QStringList define = curLine.split(" "); foundWithSpaces = findWithSpaces.match(curLine); if (define.size() == 3) c.defines.insert(std::pair<QString, QString>(define[1], define[2])); else if(foundWithSpaces.hasMatch()) c.defines.insert(std::pair<QString, QString>(define[1], foundWithSpaces.captured(1))); fileContents.removeAt(idx); } else if (curLine.startsWith("#include")) { foundWithSpaces = findWithSpaces.match(curLine); if (foundWithSpaces.hasMatch()) { QString newFilename = foundWithSpaces.captured(1); for(auto define : c.defines) { newFilename.replace(define.first, define.second); } QStringList newFileContents = readFile(path + "/" + newFilename); if (newFileContents.empty()) return false; int offset = 1; for (QString newFileLine : newFileContents) { fileContents.insert(idx+offset, newFileLine); offset++; } fileContents.removeAt(idx); } } else if (curLine.isEmpty()) fileContents.removeAt(idx); else idx++; } int total = fileContents.size(); SfzRegion r; SfzRegion g; // group SfzRegion glob; r.init(path); g.init(path); glob.init(path); bool groupMode = false; bool globMode = false; zerberus->setLoadProgress(0); for (int idx = 0; idx < fileContents.size(); idx++) { QString curLine = fileContents[idx]; zerberus->setLoadProgress(((qreal) idx * 100) / (qreal) total); if (zerberus->loadWasCanceled()) return false; if (curLine.startsWith("<global>")) { if (!globMode && !groupMode && !r.isEmpty()) addRegion(r); glob.init(path); g.init(path); // global also resets group r.init(path); globMode = true; } if (curLine.startsWith("<group>")) { if (!groupMode && !globMode && !r.isEmpty()) addRegion(r); g.init(path); if (globMode) { glob = r; globMode = false; } else { r = glob; // initialize group with global values } groupMode = true; curLine = curLine.mid(7); } else if (curLine.startsWith("<region>")) { if (groupMode) { g = r; groupMode = false; } else if (globMode) { glob = r; g = glob; globMode = false; } else { if (!r.isEmpty()) addRegion(r); r = g; // initialize next region with group values } curLine = curLine.mid(8); } else if (curLine.startsWith("<control>")) c.init(); QRegularExpression re("\\s?([\\w\\$]+)="); // defines often use the $-sign QRegularExpressionMatchIterator i = re.globalMatch(curLine); while (i.hasNext()) { QRegularExpressionMatch match = i.next(); int si = match.capturedEnd(); int ei; if (i.hasNext()) { QRegularExpressionMatch nextMatch = i.peekNext(); ei = nextMatch.capturedStart(); } else ei = curLine.size(); QString s = curLine.mid(si, ei-si); r.readOp(match.captured(1), s, c); } } for (int i = 0; i < 128; i++) _setcc[i] = c.set_cc[i]; zerberus->setLoadProgress(100); if (!groupMode && !globMode && !r.isEmpty()) addRegion(r); return true; }
void playground(QApplication& a) { std::vector<int> l1 = { 0,1,3,6,9,11 }; auto fromItem = std::upper_bound(l1.begin(), l1.end(), 2 , [](const auto &a, const auto &b) { return a > b; }); return; TextColorize::List _coloredTextParts; auto match = [&_coloredTextParts](const QString& text, Part::List& parts) { QRegularExpression::PatternOptions options; /*if (tc.caseSensitive == false) options |= QRegularExpression::PatternOption::CaseInsensitiveOption; */ QString rePattern; foreach(TextColorize ctp, _coloredTextParts) { QString pattern; if (ctp.caseSensitive == false) pattern += "(?i)"; pattern += ctp.text; pattern.prepend("(").append(")"); if(ctp.wordOnly) pattern.prepend("(?:^|[^\\w])").append("(?:[^\\w]|$)"); rePattern += "|" + pattern; } rePattern = rePattern.mid(1); QRegularExpression re(rePattern, options); QRegularExpressionMatchIterator it = re.globalMatch(text); int nonMatchedStart = 0; bool hasMatches = it.hasNext(); while (it.hasNext()) { QRegularExpressionMatch match = it.next(); int matchedGroup = match.lastCapturedIndex(); while (match.capturedTexts().at(matchedGroup).length() && --matchedGroup); qDebug() << match.capturedTexts() << " - " << match.capturedView() << " - " << match.hasPartialMatch() << " - " << matchedGroup; int nonMatechedEnd = match.capturedStart(0); int nonMatchedLength = nonMatechedEnd - nonMatchedStart; //auto& ct = _coloredTextParts[match.lastCapturedIndex() - 1]; auto& ct = _coloredTextParts[0]; if (nonMatchedLength) ;// parts.push_back({ text.mid(nonMatchedStart, nonMatchedLength), nullptr }); parts.push_back({ text.mid(match.capturedStart(0), match.capturedLength(0)), match.lastCapturedIndex() }); nonMatchedStart = match.capturedEnd(0); } if (nonMatchedStart < text.length()) parts.push_back({ text.mid(nonMatchedStart), false }); return hasMatches; };