Найти шаблон, но не внутри комментария C ++ - PullRequest
0 голосов
/ 24 января 2019

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

Мое первоначальное регулярное выражение:

foo$|foo\s|foo\[|foo\*|<foo|foo>

Совпадения: foo в конце строки, foo с пробелом, указатель foo, foo в коллекции и т. Д ...

Я хочу исключить экземпляров, которые находятся в блоке комментариев C ++. Например, в приведенном ниже примере.

// consume the foo and read another.

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

(?!\/\/).*(foo$|foo\s|foo\[|foo\*|<foo|foo>)

Кто-нибудь знает, как сделать это в регулярном выражении?

Обновление:

Я просто хочу отфильтровать строки, которые могут иметь две косые черты, предшествующие целевому шаблону. Меня не волнуют вложенные комментарии, комментарии в стиле C (/ * * /) или что-нибудь, занимающее несколько строк.

Ответы [ 2 ]

0 голосов
/ 24 января 2019

Вот довольно исчерпывающее регулярное выражение для того, что вы просите (протестировано в Perl):

my $foo_regex = qr{
    \G
    (?>
        # // comment
        / (?: \\ \n )*+ / (?> \\ \n | [^\n] )*+
    |
        # /* comment */
        / (?: \\ \n )*+ \* (?> .*? \* (?: \\ \n )*+ / )
    |
        # 'c'
        ' (?: [^'\\\n] | \\ . )++ '
    |
        # "string"
        " (?: [^"\\\n] | \\ . )*+ "
    |
        # R"(raw string)"
        \b
        (?: (?> [LU] | u (?: \\ \n )*+ 8?+ ) (?: \\ \n )*+ )?+
        R
        (?: \\ \n )*+
        "
        (?: \\ \n )*+
        ( [^()\\\s]?+ )
        (?: \\ \n )*+
        ( [^()\\\s]?+ )
        (?: \\ \n )*+
        ( [^()\\\s]?+ )
        (?: \\ \n )*+
        ( [^()\\\s]?+ )
        (?: \\ \n )*+
        ( [^()\\\s]?+ )
        (?: \\ \n )*+
        ( [^()\\\s]?+ )
        (?: \\ \n )*+
        ( [^()\\\s]?+ )
        (?: \\ \n )*+
        ( [^()\\\s]?+ )
        (?: \\ \n )*+
        ( [^()\\\s]?+ )
        (?: \\ \n )*+
        ( [^()\\\s]?+ )
        (?: \\ \n )*+
        ( [^()\\\s]?+ )
        (?: \\ \n )*+
        ( [^()\\\s]?+ )
        (?: \\ \n )*+
        ( [^()\\\s]?+ )
        (?: \\ \n )*+
        ( [^()\\\s]?+ )
        (?: \\ \n )*+
        ( [^()\\\s]?+ )
        (?: \\ \n )*+
        ( [^()\\\s]?+ )
        (?: \\ \n )*+
        \(
        (?>
            .*?
            \)
            (?: \\ \n )*+
            \g{-16}
            (?: \\ \n )*+
            \g{-15}
            (?: \\ \n )*+
            \g{-14}
            (?: \\ \n )*+
            \g{-13}
            (?: \\ \n )*+
            \g{-12}
            (?: \\ \n )*+
            \g{-11}
            (?: \\ \n )*+
            \g{-10}
            (?: \\ \n )*+
            \g{-9}
            (?: \\ \n )*+
            \g{-8}
            (?: \\ \n )*+
            \g{-7}
            (?: \\ \n )*+
            \g{-6}
            (?: \\ \n )*+
            \g{-5}
            (?: \\ \n )*+
            \g{-4}
            (?: \\ \n )*+
            \g{-3}
            (?: \\ \n )*+
            \g{-2}
            (?: \\ \n )*+
            \g{-1}
            (?: \\ \n )*+
            "
        )
    |
        # / (not starting a comment)
        / (?! (?: \\ \n )*+ [/*] )
    |
        # identifier
        \w (?: (?: \\ \n )*+ \w )*+
    |
        # arbitrary other character
        [^/"'\w]
    )*?
    \b
    (
        f
        (?: \\ \n )*+
        o
        (?: \\ \n )*+
        o
    )
    (?!
        (?: \\ \n )*+
        \w
    )
}xms;

Обзор сложностей, которые он принимает во внимание:

  • "foo", 'foo', // foo, /* foo */ - это не вхождения foo, а строковый литерал, многосимвольная константа, однострочный комментарий и комментарий блока соответственно.
  • /* " */, // ", " /* ", '//' и т. Д. Являются комментарием, комментарием, строковым литералом и многосимвольной константой соответственно.Это означает, что вы не можете поэтапно отфильтровывать строковые литералы, комментарии и т. Д .;Вы должны проанализировать их все сразу, чтобы не перепутать содержимое цитируемой конструкции с разделителями другой цитируемой конструкции.
  • Комбинации с обратной косой чертой и новой строкой должны игнорироваться (как если бы они отсутствовали висходный файл):

      /\
      * this is a comment */
      /\
      / and so is this
      foo\
      bar  // this is a single identifier, 'foobar'
      f\
      oo  // ... but this is 'foo'
      "this is a string\\
      " <- that's not the end of the string; this is: "
    
  • Большая часть этого регулярного выражения имеет дело с необработанными строковыми литералами вида R"delim(...)delim" в сочетании с произвольными парами обратная косая черта-новая строка, которые можно вставлять где угодно.К счастью, C ++ определяет верхнюю границу не более 16 пользовательских символов-разделителей;в противном случае нам пришлось бы использовать исполняемый код / ​​генерацию динамического регулярного выражения.
  • Триграфы не обрабатываются.Если вы хотите добавить поддержку, начните с изменения каждого вхождения \\ в регулярном выражении на (?> \\ | \?\?/ ).

Обновление: для ваших упрощенных требований (найдите слово foo неперед // в строке), вы можете просто сделать ^(?:[^/]|/(?!/))*?\bfoo\b.

0 голосов
/ 24 января 2019

Регулярные выражения - не лучший инструмент для этого.

Я написал конвертер C в Delphi (https://github.com/WouterVanNifterick/C-To-Delphi),, где я использую регулярные выражения для определенных задач, но я пришел к выводу, что регулярные выражения просто не подходят для того, что вы пытаетесь сделать , Я могу сказать, потому что я попробовал это и решил отказаться от регулярных выражений, потому что все усложнялось, а просто не работало надежно.

Вы можете быстро создать что-то, что работает в 90% случаев, но если вы хотите правильно работать с вложенными комментариями или строками, которые выглядят как комментарии, синтаксический анализ является единственным вариантом.

Для этого вам не нужен полный синтаксический анализатор C ++. Вам нужно пройтись по всем символам и отслеживать, находитесь ли вы в блоке / * * /, строковом блоке или // в разделе или нет, и делать то, что вам нужно.

...