我目前正在处理一些遗留代码(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: match everything but specific pattern)
但是我不确定这是否可以完全解决我的问题,即使整个过程是一个好主意?
欢迎任何提示或反馈,关于如何进行以及做什么或不做什么! 谢谢
编辑:是的,代码是Java,并且SonarQube将此标记为问题(尽管这不是很关键)
编辑2:感谢您提供所有答案和评论,我学到了很多东西,我会尝试一下,确保选择一个作为有效答案!
答案 0 :(得分:2)
> 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 :(得分:1)
尽管我在评论中指出,sed
的正则表达式对于这项工作来说有点缺乏,但我意识到sed
仍然可以做到此事而没有太多的困惑。诀窍是首先保护要保留的下划线,然后删除下划线,然后还原受保护的下划线。如果可以的话,可以使用一种有机化学方法来解决这个问题。
为此,您可以依靠以下事实:除非使用sed
命令,否则sed
的模式空间中将永远不会有一个字符 :换行符。 sed
在输入上剥离它们,(通常)在输出上发出新的,但是如果它们确实出现在模式空间中,那么它们就不是特别的了。所以考虑一下:
sed -i -e 's/([^ \t])_/\1\n/g; s/_([a-z])/\1/g; s/\n/_/g' "$file"
执行了三个替换:
再次记住,sed
在输入上去除换行符,并在普通输出上追加新行,因此(3)中唯一可替换的换行符是(1)中引入的那些用于隐藏下划线的换行符想要保护免受(2)中的替换。
答案 2 :(得分:0)
请注意,您可能有一个变量,例如_return
,在其中删除_
会导致一个关键字。
此操作可以使用perl轻松完成,因为PCRE比sed正则表达式具有更多功能。
示例
要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
正则表达式的工作原理
"(?:\\.|[^"])*"
:匹配可能包含\"
序列的字符串文字“ ..” (*SKIP)(?!)|
:回溯关键字以放弃此匹配项:
(*SKIP)
防止在匹配字符串中当前位置之前回溯(?!)
匹配失败|
尝试与以下模式匹配\b_(?=[a-z])
:匹配_
,其后跟单词边界(作为单词字符,后跟非单词字符),再跟小写字母([a-z]
)