2017-01-25 3 views
4

Я использую std::regex r("-?[0-9]*(.[0-9]+)?(e-?[0-9]+)?") для проверки чисел (ints/fixed point/floating point). MWE ниже:Уменьшение std :: regex время компиляции в C++

#include <iostream> 
#include <string> 
#include <vector> 
#include <regex> 
#include <algorithm> 

using namespace std; 

bool isNumber(string s) { 
    // can ignore all whitespace 
    s.erase(remove(s.begin(), s.end(), ' '), s.end()); 
    std::regex r("-?[0-9]*(.[0-9]+)?(e-?[0-9]+)?"); 
    return regex_match(s, r); 
} 

int main() { 
    std::vector<string> test{ 
    "3", "-3", // ints 
     "1 3", " 13", " 1 3 ", // weird spacing 
     "0.1", "-100.123123", "1000.12312", // fixed point 
     "1e5", "1e-5", "1.5e-10", "1a.512e4", // floating point 
     "a", "1a", "baaa", "1a", // invalid 
     "1e--5", "1e-", //invalid 
     }; 

    for (auto t : test) { 
    cout.width(20); cout << t << " " << isNumber(t) << endl; 
    } 

    return 0; 
} 

Я замечаю время компиляции достаточно велика по сравнению с тем, что я ожидал:

  • gcc 5.4 -O0 -std=c++11 2,3 секунды
  • gcc 5.4 -O2 -std=c++11, 3,4 секунды
  • clang++ 3.8 -O0 -std=c++11, 1,8 секунд
  • clang++ 3.8 -O2 -std=c++11, 3,7 секунды

Я использую это для онлайн-подачи судимости, у которого есть время на этапе компиляции.

Итак, obivous вопросы:

  • почему время компиляции так велика? У меня создается впечатление, что при использовании регулярных выражений в vim/emacs/grep/ack/ag и т. Д. (На той же машине) компиляция действительно занимает намного меньше.
  • есть ли способ уменьшить время компиляции регулярного выражения в C++?
+0

Это не так много времени компиляции регулярного выражения, но все кода, необходимого для реализации все функции регулярного выражения. Сравните время с использованием 10 регулярных выражений. – chris

+0

Похоже, @chris прав. Попробуйте выполнить компиляцию с -save-temps и посмотрите размер полученных промежуточных файлов. –

+0

Регулярное выражение, вероятно, собирается построить конечный конечный автомат на заднем конце. Это занимает много времени. Скорее всего, это то, что вы видите. – NathanOliver

ответ

1

Вы можете, конечно, облегчить вычислительную нагрузку вашего регулярного выражения с помощью соответствующим образом избежать десятичной точки: -?[0-9]*(\.[0-9]+)?(e-?[0-9]+)? Это, конечно, мешает вам от возвращения ложных срабатываний на номера, как: «1 3» (не волнуйтесь, это хорошо, что это были 2 номера.) Но в этом случае и многие другие, когда вы наклоняетесь на использование регулярных выражений "Now you have 2 problems".

Использование istringstream обеспечит более специализированное, надежное решение этой проблемы:

bool isNumber(const string& s) { 
    long double t; 
    istringstream r(s); 

    return r >> t >> ws && r.eof(); 
} 

Live Example

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