Sed для удаления подчеркивания и продвижения персонажа - PullRequest
7 голосов
/ 29 июня 2010

Я пытаюсь перенести некоторый код из старой схемы именования в новую, старая схема именования:

int some_var_name;

Новый -

int someVarName_:

Итак, я бы сказал, что это некая форма добра / регулярности, которая облегчит процесс. Итак, что в основном должно произойти:
найдите слово в нижнем регистре, содержащее _, замените подчеркивание ничем и добавьте символ справа от _ в верхний регистр. После этого добавляем _ в конец матча.

Возможно ли это сделать с помощью Sed и / или Awk и regex? Если нет, то почему?

Любые примеры сценариев приветствуются.

Большое спасибо за любую помощь.

EDIT:
Для большей ясности переименование предназначено для ряда файлов, которые были написаны с неправильным соглашением об именах и должны быть приведены в соответствие с остальной базой кода. Не ожидается, что это сделает идеальную замену, которая оставит все в состоянии компиляции. Скорее всего, скрипт будет запущен, а затем просмотрен вручную на предмет любых аномалий. Сценарий замены был бы просто для того, чтобы облегчить бремя необходимости исправить все вручную, что, я уверен, вы согласитесь, значительно утомительно.

Ответы [ 3 ]

4 голосов
/ 29 июня 2010

sed -re 's,[a-z]+(_[a-z]+)+,&_,g' -e 's,_([a-z]),\u\1,g'

Объяснение:

Это команда sed с двумя выражениями (каждое в кавычках после -e.) s,,,g является глобальной заменой.Вы обычно видите это с косыми чертами вместо запятых, но я думаю, что это легче читать, когда вы используете обратную косую черту в шаблонах (и без запятых).Конечный g (для «global») означает применять эту замену ко всем совпадениям в каждой строке, а не только к первой.

Первое выражение добавит подчеркивание к каждому токену, составленному из строчных слов ([a-z]+), за которым следует ненулевое количество строчных слов, разделенных подчеркиванием ((_[a-z]+)+).Мы заменим это на &_, где & означает «все, что соответствует», а _ - это буквальное подчеркивание.Таким образом, в целом, это выражение говорит о добавлении подчеркивания в конец каждого underscore_separated_lowercase_token.

Второе выражение соответствует шаблону _([a-z])), где все между ( и ) является группой захвата.Это означает, что мы можем обратиться к нему позже как \1 (потому что это первая группа захвата. Если бы их было больше, они были бы \2, \3 и т. Д.).Таким образом, мы говорим, чтобы соответствовать строчной букве после подчеркивания, и запомнить букву.

Мы заменим ее на \u\1, что является буквой, которую мы только что запомнили, но сделали заглавной буквой \u.

Этот код не делает ничего умного, чтобы избежать разбрасывания #include строк и т. П .;он будет заменять каждый экземпляр строчной буквы после подчеркивания его заглавным эквивалентом.

3 голосов
/ 29 июня 2010

Несколько лет назад я успешно преобразовал устаревшую 23 000-летнюю базу кода LOC 300 000 в camelCase. Это заняло всего два дня. Но было несколько затяжных аффектов, которые потребовались пару месяцев, чтобы разобраться. И это очень хороший способ раздражать ваших коллег-кодеров.

Я считаю, что простой, тупой, подобный седу подход имеет преимущества. Насколько мне известно, инструменты на основе IDE и т. П. Не могут:

  • изменить код не скомпилировано с помощью # ifdef's
  • изменить код в комментариях

А устаревший код нужно было поддерживать на нескольких разных платформах компилятора / ОС (= много #ifdefs).

Основным недостатком глупого, подобного седу подхода является то, что строки (например, ключевые слова) могут быть случайно изменены. И я сделал это только для C; C ++ может быть еще одним котелком рыбы.

Есть около пяти этапов:

1) Generate a list of tokens that you wish to change, and manually edit.
2) For each token in that list, determine the new token.
3) Apply these changes to your code base.
4) Compile.
5) Double-check via a manual diff, and do a final clean-up.

На шаге 1, чтобы сгенерировать список токенов, которые вы хотите изменить, введите команду:

cat *.[ch] | sed 's/\([_A-Za-z0-9][_A-Za-z0-9]*\)/\nzzz \1\n/g' | grep -w zzz | sed 's/^zzz //' | grep '_[a-z]' | sort -u > list1

будет производить в списке 1:

st_atime
time_t
...

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

Следующим шагом, 2, является создание сценария для внесения изменений. Например, команда:

cat list1 | sed 's/\(.*\)/glob_sub "\\<\1\\>" xxxx_\1/;s/\(xxxx_.*\)_a/\1A/g;s/\(xxxx_.*\)_b/\1B/g;s/\(xxxx_.*\)_a/\1C/g;s/\(xxxx_.*\)_t/\1T/g' | sed 's/zzz //' > list2

изменит _a, _b, _c и _t на A, B, C и T, чтобы произвести:

glob_sub "\<st_atime\>" xxxx_stAtime
glob_sub "\<time_t\>" xxxx_timeT

Вы просто должны расширить его, чтобы охватить d, e, f, ..., x, y, z,

Я предполагаю, что вы уже написали что-то вроде 'glob_sub' для своей среды разработки. (Если нет, откажитесь сейчас.) Моя версия (csh, Cygwin) выглядит так:

#!/bin/csh
foreach file (`grep -l "$1" */*.[ch] *.[ch]`)
  /bin/mv -f $file $file.bak
  /bin/sed "s/$1/$2/g" $file.bak > $file
end

(Некоторые из моих sed не поддерживают опцию --in-place, поэтому я должен использовать mv.)

Третий шаг - применить этот скрипт в списке list2 к вашей базе кода. Например, в csh используйте source list2.

Четвертый шаг - компиляция. Компилятор будет (надеюсь!) Возражать против xxxx_timeT. Действительно, он, скорее всего, должен возражать против timeT, но дополнительные xxx_ добавляют страховку. Так что для time_t вы ошиблись. Отмените его, например,

glob_sub "\<xxxx_timeT\>" time_t

Пятым и последним шагом является ручная проверка ваших изменений с использованием вашей любимой утилиты diff, а затем очистка путем удаления всех нежелательных префиксов xxx_. Grepping для "xxx_ также поможет проверить наличие токенов в строках. (Действительно, добавление суффикса _xxx, вероятно, является хорошей идеей.)

3 голосов
/ 29 июня 2010

Попробуйте использовать sed для поиска и замены всего текста следующим образом.Если токенайзер C ++ не распознает идентификаторы (и, в частности, ваши идентификаторы, а не идентификаторы в стандартной библиотеке, например), вы ввернуты .push_back переименовывается в pushBack_.карта :: вставить на карту :: вставить_.map to map_.Basic_string to basicString_.printf в printf_ (если вы используете библиотеки C) и т. д. Вы попадете в мир боли, если будете делать это без разбора.

Я не знаю ни одного существующего инструмента для автоматического переименования some_var_name вsomeVarName_ без проблем, описанных выше.Люди проголосовали за этот пост, вероятно, потому что они не поняли, что я имел в виду здесь.Я не говорю, что sed не может этого сделать, Я просто говорю, что это не даст вам того, что вы хотите , чтобы использовать его как есть.Парсеру нужна контекстная информация, чтобы сделать это правильно, иначе он заменит намного больше вещей, чем не должен.

Можно было бы написать парсер, который бы это делал (например, используя sed) если бы он мог распознать, какие токены были идентификаторами (в частности, ваши идентификаторы), но я сомневаюсь, что есть инструмент, специально предназначенный для того, что вы хотите сделать, который делает это с нуля без какой-либо ручной смазки локтя (хотя я могу ошибаться).Выполнение простого поиска и замены по всему тексту таким способом было бы проблематично.

Однако Visual AssistX (который может при необходимости заменять экземпляры в документации) или любой другой инструмент рефакторинга, способный интеллектуально переименовывать идентификаторы для каждого экземпляра, в которомони происходят, по крайней мере, значительно облегчают бремя рефакторинга кода таким способом.Если у вас есть символ с именем some_var_name, и на него ссылаются тысячи различных мест в вашей системе, с помощью VAssistX вы можете просто использовать одну функцию переименования, чтобы разумно переименовать все ссылки (это не просто текстовый поиск и замена). Ознакомьтесь с функциями рефакторинга Visual Assist X .

Для рефакторинга сотен переменных таким образом с помощью VAX может потребоваться от 15 минут до получаса (быстрее, если вы используете горячие клавиши), ноэто, конечно, лучше, чем использование текстового поиска и замена на sed, как описано в другом ответе, и замена всех видов кода, которые не должны быть заменены.

[субъективно] Кстати: подчеркивания по-прежнему нетпринадлежат в случае верблюда, если вы спросите меня.Соглашение об именовании lowerCamelCase должно использовать lowerCamelCase.Есть много интересных статей по этому вопросу, но, по крайней мере, ваша конвенция последовательна.Если это согласуется, то это огромный плюс по сравнению с чем-то вроде fooBar_Baz, которое пишут некоторые глупые программисты, которые думают, что это как-то упрощает создание особых исключений из правила. [/ Subjective]

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...