2015-12-10 2 views
1

Давайте предположим, для простоты, мы имеем следующую строку:Multiple замена только с одним регулярным выражением

«Джон любит Мэри, Мэри любит Джейка и Джейк не заботится о Джоне и Мэри.»

Предположим, я хочу использовать регулярное выражение для изменения персонажей этой истории.

Джон -> Джозеф

Mary -> Джессика

Джейк -> Кит

Конечно, я могу изменить, который один из них, один за один раз.

Но я хотел бы знать, можно ли изменить их все с помощью только одной замены регулярного выражения, например, «множественная замена» или «условная замена».

Что-то вроде:

регулярное выражение: (?:(?<name1>John)|(?<name2>Mary)|(?<name3>Jake))

замена: (?(name1)Joseph|(?(name2)Jessica|(?(name3)Keith)))

Это лишь простой пример.

В моем приложении я должен выполнить около 20 замен для каждой строки, что влияет на производительность приложения.

Являясь регулярным выражением, я использую PCRE.

Приложение кодируется с использованием C++ с картой Qt.

+0

Вы не можете использовать шаблон регулярного выражения в заменяющей строке или какие-либо условия. Тогда вам нужен обратный вызов. –

+0

@stribizhev не обязательно, некоторые библиотеки предоставляют такую ​​возможность (см. Мой ответ) ;-) –

ответ

1

Итак, вы используете так называемый PCRE аромат. Хорошо, если не сказать точно, какую библиотеку вы используете. Давайте рассмотрим несколько вариантов здесь, так как несколько разных библиотек утверждают, что они совместимы с Perl.

подталкивания

Это самое простое решение. boost::regex поддерживает именно то, что вы просите, через его Boost-Extended Format String Syntax.

Таким образом, вы можете заменить шаблон:

(?<name1>John)|(?<name2>Mary)|(?<name3>Jake) 

С строкой замены:

(?{name1}Joseph:(?{name2}Jessica:Keith)) 

И конечно, это работает. Вы можете проверить его в Notepad ++, но вот некоторые примеры кода:

#include <string> 
#include <iostream> 
#include <boost/regex.hpp> 

int main(int argc, char **argv) { 
    std::string subject("John loves Mary, Mary loves Jake and Jake doesn't care about John and Mary."); 
    const char* replacement = "(?{name1}Joseph:(?{name2}Jessica:Keith))"; 

    boost::regex re("(?<name1>John)|(?<name2>Mary)|(?<name3>Jake)", boost::match_perl); 

    std::string result = boost::regex_replace(subject, re, replacement, boost::format_all); 
    std::cout << result << std::endl; 

    return 0; 
} 

PCRE2

PCRE catched up с Boost, и ввел богатый синтаксис подстановки через PCRE2_SUBSTITUTE_EXTENDED. Начиная с этого поста (v10.20), этот код еще не выпущен, но он доступен в исходном репозитории (версия 381), поэтому, если вам нужно это решение сейчас, вам придется построить PCRE2 из источника.

картина та же, но строка замены имеет другой синтаксис:

${name1:+Joseph:${name2:+Jessica:Keith}} 

Вот некоторые примеры C код:

#include <stdio.h> 
#include <string.h> 

#define PCRE2_CODE_UNIT_WIDTH 8 
#include <pcre2.h> 

int main(int argc, char **argv) { 
    int error; 
    PCRE2_SIZE erroffset; 

    const PCRE2_SPTR pattern = (PCRE2_SPTR)"(?<name1>John)|(?<name2>Mary)|(?<name3>Jake)"; 
    const PCRE2_SPTR subject = (PCRE2_SPTR)"John loves Mary, Mary loves Jake and Jake doesn't care about John and Mary."; 
    const PCRE2_SPTR replacement = (PCRE2_SPTR)"${name1:+Joseph:${name2:+Jessica:Keith}}"; 

    pcre2_code *re = pcre2_compile(pattern, PCRE2_ZERO_TERMINATED, 0, &error, &erroffset, 0); 
    if (re == 0) 
     return 1; 

    pcre2_jit_compile(re, PCRE2_JIT_COMPLETE); 

    PCRE2_UCHAR output[1024] = ""; 
    PCRE2_SIZE outlen = sizeof(output)/sizeof(PCRE2_UCHAR); 

    int rc = pcre2_substitute(re, subject, PCRE2_ZERO_TERMINATED, 0, PCRE2_SUBSTITUTE_GLOBAL | PCRE2_SUBSTITUTE_EXTENDED, 0, 0, replacement, PCRE2_ZERO_TERMINATED, output, &outlen); 
    if (rc >= 0) 
     printf("%s\n", output); 

    pcre2_code_free(re); 
    return 0; 
} 

PCRE

С PCRE (< v10), не повезло тебе. В нем отсутствует функция замены, это остается для разработчика.

... это означает, что если это библиотека, которую вы используете, вы все равно будете иметь полный контроль над процессом замещения. Вы можете использовать шаблон, такие как:

John(*MARK:1)|Mary(*MARK:2)|Jake(*MARK:3) 

А потом, заменить на дискриминацию на последний встречается MARK.

Qt

QRegularExpression класс в Qt инкапсулирует библиотеку PCRE (не PCRE2), но это, похоже, не подвергать все функции PCRE.

Во всяком случае, QString::replace overload который принимает QRegularExpression не выглядит так, как это полнофункциональный:

QString & QString::replace(const QRegularExpression & re, const QString & after) 

Таким образом, вы по своему усмотрению здесь.

Мои 2 цента

Эй, может быть такой простой замены, регулярное выражение является излишеством ... Если у вас есть проблемы с производительностью, вы должны попытаться реализовать эти замены вручную - тщательно разработанный алгоритм должен быстрее, чем регулярное выражение. Просто убедитесь, что вы прокомментируете свой код и посмотрите, где находится преступник.

Смежные вопросы