Удаление _ в именах переменных с помощью sed - PullRequest
0 голосов
/ 20 марта 2019

В настоящее время я работаю над некоторым устаревшим кодом (проект Java), и многие переменные (15k) имеют подчеркивание в качестве первого символа, например:

_iAmAInt //should be iAmInt

(все заменяемые переменные начинаются с _, за которым следует строчная буква)

Так что я подумал, что попробую почистить это с помощью небольшого скрипта с sed и regex, пока что вот что у меня получилось:

while IFS= read -r -d '' file; do
   if [[ $file == *.java ]]; then 

        sed -i -E 's/([_])([a-z])/\2/g' $file

    fi  
done < <(find "$1" -type f -print0)

Дело в том, что в некоторых случаях у меня есть несколько строк (например, запросов), которые имеют что-то вроде этого: "select house_id from houses"

Мое текущее регулярное выражение не принимает это во внимание, но, очевидно, мне нужно как-то указать, что _ между "" не должно быть удалено.

Из того, что я прочитал, я мог бы использовать отрицательный прогноз ( Regex: сопоставить все, кроме определенного шаблона )

Но я не совсем уверен, что это полностью решит мою проблему, или даже если весь процесс будет хорошей идеей?

Любые намеки или отзывы о том, как действовать и что делать или нет, приветствуются! Спасибо

Редактировать: Да, это код Java, и SonarQube помечает это как проблему (хотя это не очень важно)

Редактировать 2: Спасибо за все ответы и комментарии, я многому научился, попробую их и обязательно выберу правильный ответ!

Ответы [ 3 ]

2 голосов
/ 20 марта 2019
> sed -E 's/("([^"\\]|\\.)*")|_([a-z0-9]+)|([a-z][a-z0-9_]+)/\1\3\4/g'
foo _bar foo_bar " \" _zoo \" "
foo bar foo_bar " \" _zoo \" "

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

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

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

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

sed -i -e 's/([^ \t])_/\1\n/g; s/_([a-z])/\1/g; s/\n/_/g' "$file"

Выполнены три замены:

  1. каждое подчеркивание, которое не следует сразу после пробела или табуляции, заменяется новой строкой;
  2. (изменение вашего исходного регулярного выражения :) удаляется каждое подчеркивание, за которым следует строчная латинская буква;и
  3. каждая новая строка заменяется подчеркиванием.

Помните, опять же, что sed удаляет новые строки на входе и добавляет новые на обычном выходе, поэтому единственные новые строки доступны длязамена в (3) - это те, которые были введены в (1), чтобы скрыть подчеркивания, которые вы хотите защитить от замены в (2).

0 голосов
/ 20 марта 2019

Обратите внимание, что у вас может быть переменная, подобная _return, где удаление _ приведет к ключевому слову.

Эту операцию можно легко выполнить с помощью perl, поскольку PCRE имеет большеОсобенности, чем SEG регулярных выражений.

Примеры

для grep, просто отображать совпадения.

# where ... are find options e.g. `-name '*.java'`
find "$1" -type f ... -exec perl -ne 'print "$ARGV:$_" if /"(?:\\.|[^"])*"(*SKIP)(?!)|\b_[a-z]/' {} +

, чтобы изменить файлы на месте: (-i как sed -i.bak, вPerl по умолчанию исходные файлы перемещаются в .bak)

find "$1" -type f ... -exec perl -i -pe 's/"(?:\\.|[^"])*"(*SKIP)(?!)|\b_(?=[a-z])//g' {} +

для восстановления: заменить на .bak файлов

find "$1" -type f ... -name '*.bak' -exec bash -c 'for f; do mv "$f" "${f%.bak}"; done' bash {} +

для удаления .bak файлов

find "$1" -type f ... -name '*.bak' -delete

Как работает регулярное выражение

  • "(?:\\.|[^"])*": соответствует строковому литералу "..", который может содержать \" sequence
  • (*SKIP)(?!)|: ключевое слово backtracking для удаления этогоmatch:
    • (*SKIP) предотвращать возврат назад до текущей позиции в совпадающей строке
    • (?!) при неудачном совпадении
    • |, чтобы попытаться сопоставить следующий шаблон
  • \b_(?=[a-z]): для сопоставления _ с предшествующей границей слова (как символ слова, которому предшествует символ без слова)а затем строчная буква ([a-z])
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...