我有以下文字:
SendNoticeMsg (api.post = "/test/SendNoticeMsg")
GenerateMsg (api.post = "/test/GenerateMsg")
GetUserLastAction (api.post = "/test/GetUserLastAction")
我想将文本更改为:
SendNoticeMsg (api.post = "/test/send_notice_msg")
GenerateMsg (api.post = "/test/generate_msg")
GetUserLastAction (api.post = "/test/get_user_last_action")
描述:我只想将 URL 路径更改为有效的下划线样式,因此解决方案不应更改任何其他不相关的字符。
我尝试使用 sed 脚本:
sed -E 's/(/test/.*)([A-Z]).*"/12_L/'
但它不起作用。
perl -wnE'
@p = m{(.*/)(.*)"}; # break up into parts
@w = $p[-1] =~ /([A-Z][a-z0-9]*)/g; # extract (PascalCase-ed) words
$p[-1] = join("_", map { lc } @w).q{")}; # low-case them, join with _
say @p
' input.txt
或者通过将开关更改为perl -i.bak -wnE'...'
来"就地"覆盖输入
这假设单词,在首字母之后,只能有[a-z0-9]
;如果需要,可以调整。
另一个 perl 解决方案:
$ perl -pe '$i=0; s/(?=/test/)(S+)/$s=$1;$s=~s!([A-Z])!$i++?"_".lc($1):lc($1)!ge;$s/ge ' underscore2.txt
SendNoticeMsg (api.post = "/test/send_notice_msg")
GenerateMsg (api.post = "/test/generate_msg")
GetUserLastAction (api.post = "/test/get_user_last_action")
$
进一步增强。
$ perl -pe '$i=0; s/(?=/[^/]+/)(S+)/$s=$1;$s=~s!([A-Z])!$i++?"_".lc($1):lc($1)!ge;$s/ge ' underscore2.txt
SendNoticeMsg (api.post = "/test/send_notice_msg")
GenerateMsg (api.post = "/test/generate_msg")
GetUserLastAction (api.post = "/test/get_user_last_action")
$
perl -pe's{/test/K[^"]*}{ lc( $& =~ s/wK(?=p{Lu})/_/gr ) }e'
甚至
perl -pe's{/test/K[^"]*}{ lc( $& =~ s/B(?=p{Lu})/_/gr ) }e'
我们提取路径,并将其替换为由替换表达式构造的字符串。我们通过在适当的位置(在单词字符和大写字母之间)插入下划线来构造该字符串,然后将结果小写。
请参阅指定要处理的文件到 Perl 单行。
我将在组合中添加一个sed
,通过使用#
作为替代替换分隔符@tripleee答案略有不同,例如
sed -E ':a;s#^(.*/)([^A-Z]*)([A-Z])#1L2_3#;ta;s#/_#/#'
该^(.*/)
允许从每行的开头到最后'/'
对所有字符进行贪婪匹配。
示例使用/输出
$ sed -E ':a;s#^(.*/)([^A-Z]*)([A-Z])#1L2_3#;ta;s#/_#/#' file
SendNoticeMsg (api.post = "/test/send_notice_msg")
GenerateMsg (api.post = "/test/generate_msg")
GetUserLastAction (api.post = "/test/get_user_last_action")
(注意:如果不使用 GNUsed
则需要将每个';'
替换为-e
以标记单独的表达式)
如果由于某种原因您的sed
不支持 ERE,那么像 BRE 这样的"纠察围栏"将是:
sed ':a;s#^(.*/)([^A-Z]*)([A-Z])#1L2_3#;ta;s#/_#/#'
下面是一个Perl单行:
perl -pe 'sub to_snake { my $v = $_[0]; $v =~ s/([a-z])([A-Z])/$1_$2/g; return lc $v; } s@(/test/)(w+)@$1.to_snake $2@e'
请注意,您可以在此处更改w
以满足您的需求,但对于大多数目的来说应该足够了。
分解一下:
Perl 的-p
参数读取输入并写入标准输出;-e
允许在命令行上将程序指定为字符串。
这部分在每一行上执行替换;它使用e
修饰符来执行代码:
s@(/test/)(w+)@$1.to_snake $2@e'
这部分定义了转换函数;它匹配大写字母前面的小写字母,在它们之间添加一个下划线,然后使用 Perl 的lc
函数将所有内容映射到小写:
sub to_snake { my $v = $_[0]; $v =~ s/([a-z])([A-Z])/$1_$2/g; return lc $v; }
简单的sed
脚本执行单个替换。您希望添加一个循环以使其匹配并根据需要多次替换。
sed -E -e ':a' -e 's/(/test/.*)([A-Z])(.*")/1_L23/' -e 'ta' -e 's%/_%/%'
:a
将创建一个标签a
,并在最新的替换成功时ta
分支返回到该标签。(我盲目地假设脚本的其他部分对你来说是正确的;-E
选项的可用性以及它是否为小写提供转义L
绝不是通用的或可移植的,尽管我不得不重构它一点,并为/test/_whatever/
添加修复。
似乎所有的答案都使用perl
所以这里有一个使用awk
awk -F '"' '{
gsub(/([^/][A-Z])/," & ", $2);
n=split($2,c," ");
s=""
for (i=1; i<=n; i++) {
s = (i%2==1) ? (s c[i]) : (s substr(c[i],1,1) "_" substr(c[i], 2, 1));
}
$2=tolower(s);
print $1 """ $2 """ $3;
}' input.txt
它假设没有可用的捕获组或gensub
,因此它用空格分隔组以稍后插入_
。
假设每行有 0 或 2 个"
,并且只对更改它们之间的内容感兴趣,您可能会使用以下方式AWK
。让file.txt
内容成为
SendNoticeMsg (api.post = "/test/SendNoticeMsg")
GenerateMsg (api.post = "/test/GenerateMsg")
GetUserLastAction (api.post = "/test/GetUserLastAction")
然后
BEGIN{FS=OFS="""}{while(match($2,/[a-z][A-Z]/)){$2 = substr($2, 1, RSTART) "_" substr($2, RSTART+1)};$2=tolower($2);print}
输出
SendNoticeMsg (api.post = "/test/send_notice_msg")
GenerateMsg (api.post = "/test/generate_msg")
GetUserLastAction (api.post = "/test/get_user_last_action")
解释 我将字段分隔符和输出字段分隔符都设置为"
,然后我更改$2
("
内部的内容)如下:只要有小写字母后跟大写字母,它们之间就插入_
。最后,我将整个$2
更改为小写。(在Gawk 4.2.1中测试)
/in 在锁定之前
perl -pe '$_ = lc join "_", split /(?<=[^A-Z])(?=[A-Z])/;'
my $s = "Foo1BarXBazX";
print $s =~ s/^([A-Z])|(?<=[^A-Z])([A-Z]+)/defined $1 ? "L$1" : "_L$2"; /egr;
"foo1_bar_xbaz_x"