Сопоставьте шаблон и вставьте текст после него выборочно в большой файл - PullRequest
1 голос
/ 22 марта 2019

Я работаю с очень большим размером кода и мне нужно переименовать множество API. Это включает в себя префиксы для всех API. Мои имена API выглядят примерно так:

MyfoobarFilename_FooFighterDoMeAFavor(MyfoobarFilename_FooFighter *FighterInstance, void *Favor)
MyfoobarFilename_FooFighterGetInLine(MyfoobarFilename_FooFighter *FighterInstance, void *Line)
MyfoobarFilename_FooFighterSetATicketForMe(MyfoobarFilename_FooFighter *FighterInstance, void *Ticket)
MyfoobarFilename_FooFighterHelpMeNowInterrupt(MyfoobarFilename_FooFighter *FighterInstance, void *FighterReference)
MyfoobarFilename_FooFighterAreYouOk(MyfoobarFilename_FooFighter *FighterInstance, unsigned int HowAreYou)

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

MyfoobarFilename_FooFighter_DoMeAFavor(MyfoobarFilename_FooFighter *FighterInstance, void *Favor)
MyfoobarFilename_FooFighter_GetInLine(MyfoobarFilename_FooFighter *FighterInstance, void *Line)
MyfoobarFilename_FooFighter_SetATicketForMe(MyfoobarFilename_FooFighter *FighterInstance, void *Ticket)
MyfoobarFilename_FooFighter_HelpMeNowInterrupt(MyfoobarFilename_FooFighter *FighterInstance, void *FighterReference)
MyfoobarFilename_FooFighter_AreYouOk(MyfoobarFilename_FooFighter *FighterInstance, unsigned int HowAreYou)

Однако я хочу заменить текст только в именах API, а не в других местах кода. Я мог бы использовать s/FooFighter/FooFighter_/g, но это также внесет изменения, которые я не хочу.

Я мог бы сделать это многими способами, используя скрипт, выполняя grep и заменяя.
Однако должен быть более быстрый и умный способ сделать это, используя одну команду (надеюсь, с помощью sed). Может кто-нибудь просветить меня, как это сделать.

Заранее спасибо.

Ответы [ 2 ]

1 голос
/ 22 марта 2019

Я бы порекомендовал следующее выражение sed (используя Базовое регулярное выражение * синтаксис 1003 *):

s/\(\bMyfoobarFilename_FooFighter\)\([a-zA-Z0-9_]\+\b\)/\1_\2/g

, где

  • \b escapesequence обозначает «границу слова» (расширение GNU);
  • \( ... \) создает группу, на которую можно ссылаться в части «замена» команды s/regexp/replacement/;
  • \1 и \2 являются ссылками на первую и вторую группы;
  • g дает указание sed применить замену ко всем совпадениям для "регулярного выражения", а не только для первой;
  • \+ соответствует одному или нескольким (расширение GNU).

Perl в качестве альтернативы GNU sed

Как отмечали @Wiktor Stribiżew и @Ed Morton,\+ и \b являются расширениями GNU.Вы можете заменить \+ на \{1,\}.Но я не смог найти подходящую POSIX-совместимую замену для \b.Если GNU sed недоступен, вы можете использовать Perl следующим образом:

perl -i -npe \
's/(\bMyfoobarFilename_FooFighter)(\p{L}+\b)/\1_\2/g' file

, где \p{L} - это свойство символа Unicode , обозначающее букву.Остальное похоже на приведенное выше выражение sed.


Ваши фрагменты выглядят как прототипы функций C / C ++, так что вы, вероятно, хотели бы также изменить вызовы функций и указатели функций, например:

while (MyfoobarFilename_FooFighterHelpMeNowInterrupt ()
  && MyfoobarFilename_FooFighterSetATicketForMe())
  {
    /* ... */
  }

void (*fptr)(MyfoobarFilename_FooFighter *, void *) =
  &MyfoobarFilename_FooFighterGetInLine;
0 голосов
/ 22 марта 2019

попробуйте это:

sed "s/\(MyfoobarFilename_FooFighter\)\(\S*(\)/\1_\2/g" file.txt

Объяснение:

s/                                  # substitute
\(MyfoobarFilename_FooFighter\)     # searchstring in \1
\(\S*(\)                            # the rest to the bracket in \2
/\1_\2                              # insert '_' between \1 and \2
/g                                  # global
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...