文本中每行的部分文本格式由CamelWord的形式替换为CAMEL_WORD的形式

Sed&Awk 同时被 2 个专栏收录
1 篇文章 0 订阅
2 篇文章 0 订阅

前几天遇到了一个问题,需要处理一些文本,处理要求如下:

    文本每一行中都是相同的两个部分,现在想把第一个部分格式由原来的CamelWord的格式更改为CAMEL_WORD的形式。第二部分不变。如下:

处理前的文档:

HelloWorld HelloWorld
DoSomethingSpecial DoSomethingSpecial
EnglishConditionAction EnglishConditionAction
ThisIsASentenceForTesting ThisIsASentenceForTesting

处理后的文档:

HELLO_WORLD HelloWorld
DO_SOMETHING_SPECIAL DoSomethingSpecial
ENGLISH_CONDITION_ACTION EnglishConditionAction
THIS_IS_A_SENTENCE_FOR_TESTING ThisIsASentenceForTesting

也即,每一行的文本的第一部分由原来的每个单词首字母大写的形式更改为全部大写,并且单词与单词之间使用下划线(_)分隔。


一开始,我是使用vim来做的,不过实在没找到太好的方法,只好先分成两部分。将每一行的第一个部分单独拿到一个文档A当中,然后单独处理那个文档A,再将处理结果合并到只含第二部分的文档B当中。 后来觉着这个方法太费力,所以去求助了CU shell版的大神们,得到了一些比较不错的方法,此处做个记录,以备后查。同时感谢所有提供答案的网友。【此处留待补充更好的vim解决方案


1. perl脚本方法

感谢jason680提供perl解决方法,其命令如下:

perl -lape '$F[0]=~s/([A-Z][a-z]*)/_\U${1}/g;$_="@F";s/^_//' FILE


我基本没怎么学过perl,这儿简单解释一下命令的意思。以免后面查看起来比较费劲。 解释可能不到位或者有错误,后面熟悉Perl后再回来补充。

    命令的四个参数先不管,只看表达式里面的部分。整个表达式以";"为界分为3部分(并以第一行的处理为例给出处理前后的文本示例):

        第1部分: ’$F[0]=~s/([A-Z][a-z]*)/_\U${1}/g‘ 我的理解是将每一行的第一部分使用s命令替换,将每个大写字母前面加一个下划线(_),并将整个第一部分所有的字母转换为大写。第一行文本处理后 $F[0] 的内容为:_HELLO_WORLD

        第2部分:$_="@F" 将数组的内容赋给$_(Perl的默认输入/输出), $_的内容为:_HELLO_WORLD HelloWorld

        第3部分: s/^_// 将开头的下划线(_)删除(因为没有指定对谁做替换处理,所以默认为$_), 之后$_的内容为 HELLO_WORLD HelloWorld


2. sed脚本方法

有多位网友提供sed的解决方法,分别如下:

    a. 感谢yinyuemi 提供,命令如下:

sed -r ':a;s/([[:upper:]][[:lower:]]*)([[:upper:] ].+)\1/\1\n\2\1/;ta;:b;s/([^\n ]+)\n(.+)/\U\1_\E\2/;tb;s/_ / /' file

我暂时还没有仔细分析这个命令表达式,会在之后补充说明。


b. 感谢liion631818提供,命令如下:

sed -r 's/ /\n/; h;s/[A-Z]/_&/g;s/.*/\U&/;s/^_//g;G;s/\n.*\n/ /'  file

大致说一下表达式的意思:

    对每一行(以第一行为示例):

        将空格替换为'\n', (HelloWorld\nHelloWorld)

        将替换后的内容存储到hold space当中

        将pattern space当中的所有大写字母前添加下划线(_) (_Hello_World\n_Hello_World)

        将pattern space当中的所有字符替换为大写;(_HELLO_WORLD\n_HELLO_WORLD)

        之后将hold space当中的内容追加到pattern space当中(_HELLO_WORLD\n_HELLO_WORLD\nHelloWorld\nHelloWorld)

        将开头的下划线删除(HELLO_WORLD\n_HELLO_WORLD\nHelloWorld\nHelloWorld)

        将第一个‘\n'到最后一个'\n'之间的内容替换为空格(HELLO_WORLD HelloWorld)

3. awk脚本方法

    同样有多位网友提供awk的解决方法,分别如下:

    a. 感谢聆雨淋夜提供,命令如下:

awk '{$1=gensub(/[[:upper:]]/,"_&","g",$1);$1=toupper($1);sub(/_/,"")}1' file

命令比较容易理解,我大致说明一下(以第一行内容示例)

    将第一个字段中的所有大写字母前加上下划线,并重新赋给$1, 即(_Hello_World HelloWorld)

    将$1的内容全部转为大写,即(_HELLO_WORLD HelloWorld)

    删除$0的第一个下划线,即(HELLO_WORLD HelloWorld)

b. 感谢zxy877298415提供,命令如下:

awk '{split($1,a,"");printf a[1];for(i=2;i<=length(a);i++){if(a[i]~/[[:upper:]]/) {printf "_"a[i]} else {printf toupper(a[i])}}print " "$2}' file

命令大致说明:

    将第一个字段分割为单个字符组成的数组a

    打印a数组的第一个元素

    从a数组的第二个元素开始,如果是大写字母,那么在其前面加前导下划线后输出;如果不是大写字母,将转为大写字母输出

    循环完成后,打印空格和第二个字段


c.感谢 LikeLx提供,命令如下:

awk '{gsub(/\B[[:upper:]]/,"_&",$1);print toupper($1),$2}' file
命令大致说明:

    跟a方法当中方法基本一致,但是此处使用\B这个来界定第一个字段当中仅仅那些前面有字符的大写字母我们才给其加上下划线,行首的字符即使是大写字符,但是由于不满足\B这个条件,所以不再添加下划线。这样就避免了,我们全部添加下划线后,在使用sub去删除的问题。



vim方法

【2015.01.10 16:13更新】

终于想到了一个vim解决方案,虽然应该也还是不完美,但是可以实现了,不过需要两个命令来实现,这个应该可以录制宏或者使用vim脚本的形式来完成。

%s:\(\w\)\@<=\(\([A-Z][a-z]*\)\+ \)\@=:_:g
%s:.* \ze.*:\U&:

简单解释一下:

第一条命令:

    匹配符合条件的位置: 前面有字符,后面是大写字母,并在该位置添加下划线(_), 另外为保证仅仅匹配空格前的部分,对于第二部分不影响,所以在

\(\([A-Z][a-z]*\)\+ \)
处"+"号后面有一个空格

第二条命令,是将空格前面的全都转为大写字母。


  • 0
    点赞
  • 0
    评论
  • 0
    收藏
  • 一键三连
    一键三连
  • 扫一扫,分享海报

©️2021 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值