【问题标题】:Sed: snake case functionsSed:蛇案例功能
【发布时间】:2018-02-15 15:53:40
【问题描述】:

我需要一个 sed 脚本来自动将 C 函数转换为小写蛇形。

到目前为止,我所拥有的是以下内容,它将用下划线分隔驼峰式单词,但它不会小写它们并且会影响所有内容。

sed -i -e 's/\([a-z0-9]\)\([A-Z]\)/\1_\L\2/g' `find source/ -type f`

如何使其仅适用于函数? IE。仅在后跟字符 '(' 的字符串上。

另外,我需要什么使字符串变为小写?

例如,如果我有这个代码:

void destroyPoolLender(PoolLender *lender)
{
    while (!isListEmpty(&lender->pools)) {
        MemoryPool *myPool = listPop(&this->pool);

        if (pool->inUse) {
            logError("%s memory pool still in use. Pool not released.", pool->lenderName);
        } else {
            free(pool);
        }
    }
    listDestroy(&this->pool);
}

转换后应该是这样的:

void destroy_pool_lender(PoolLender *lender)
{
    while (!is_list_empty(&lender->pools)) {
        MemoryPool *myPool = list_pop(&this->pool);

        if (pool->inUse) {
            log_error("%s memory pool still in use. Pool not released.", pool->lenderName);
        } else {
            free(pool);
        }
    }
    list_destroy(&lender->pools);
}

注意 myPool 是如何保持不变的,因为它不是函数名。

【问题讨论】:

  • 我认为您应该通过管道输出sed 并使用tr 将其变为小写。
  • 发布输入数据和预期结果
  • 输入数据是一个大约 70k 行代码的 C 代码库,其函数以驼峰式风格编写。预期的结果是那些转换为小写蛇形样式的函数。其余代码不得触碰。

标签: function sed case-conversion


【解决方案1】:

我们可以用 sed 做到这一点。诀窍是匹配包括( 在内的所有内容作为捕获组2,并使用\l 而不是\L,仅将第一个匹配字符小写:

s/\([a-z0-9]\)\([A-Z][A-Za-z0-9]*(\)/\1_\l\2/

我们不能只使用/g修饰符,因为后面的替换可能会重叠,所以循环使用:

#!/bin/sed -rf

:loop
s/([a-z0-9])([A-Z][A-Za-z0-9]*\()/\1_\l\2/
tloop

(我在 GNU sed 中使用了-r 来减少我需要的反斜杠数量)。

进一步的简化是匹配非单词边界;这消除了对两个捕获组的需要:

#!/bin/sed -rf

:loop
s/\B[A-Z]\w*\(/_\l&/
tloop

演示:

$ sed -r ':loop;s/\B[A-Z]\w*\(/_\l&/;tloop' \
          <<<'SomeType *myFoo = callMyFunction(myBar, someOtherFunction());'
SomeType *myFoo = call_my_function(myBar, some_other_function());

请注意,这只会修改函数调用和定义 - 如果您要存储或传递函数指针,则很难识别哪些名称是函数。如果您只有 70k 行要处理,您可能会选择手动修复它们(对编译错误做出反应)。如果您使用 1M+,您可能需要一个合适的重构工具。

【讨论】:

    【解决方案2】:

    bash 的解决方案。它通过nm 命令使用来自目标文件的信息。见man nm

    要从您需要的源文件创建目标文件,请为每个源文件运行gcc-c 选项(可能您已经拥有它们,由make 命令创建。然后,您可以跳过此步骤) :

    gcc -c one.c -o one.o
    gcc -c two.c -o two.o
    

    用法: ./convert.sh one.o two.o

    #!/bin/bash
    
    # store original function names to the variable.
    orig_func_names=$(
        # get list symbols from all object files
        nm -f sysv "$@" |
        # picks the functions and removes all information except names.
        sed -n '/FUNC/s/\s.*//p' |
        # selects only functions, which contain the uppercase letter in the name.
        sed -n '/[A-Z]/p'
    );
    
    # convert camel case names to snake case names and store new names to the variable.
    new_func_names=$(sed 's/[A-Z]/_\l&/g' <<< "$orig_func_names")
    
    # create file, containing substitute commands for 'sed'. 
    # Example of commands from this file:
    # s/\boneTwo\b/one_two/g
    # s/\boneTwoThree\b/one_two_three/g
    # etc. One line to the each function name.
    paste -d'/' <(printf 's/\\b%s\\b\n' ${orig_func_names}) <(printf '%s/g\n' ${new_func_names}) > command_file.txt
    
    # do converting
    # change object file extenstions '.o' to C source - '.c' file extensions.
    # were this filenames: one.o two.o three.o
    # now they are: one.c two.c three.c
    # this 'sed' command creates backup for the each file and change the source files. 
    sed -i_backup -f command_file.txt "${@/.o/.c}"
    

    应注意,在此解决方案中执行时间呈指数增长。 例如,如果我们有 70000 行和 1000 个函数,那么它需要进行 7000 万次检查(70000 行 * 1000 个函数)。知道需要多长时间会很有趣。


    测试

    输入

    文件one.c

    #include <stdio.h>
    
    int one(); 
    int oneTwo(); 
    int oneTwoThree();
    int oneTwoThreeFour();
    
    int one() {
        puts("");
        return 0;
    }
    
    int oneTwo() {
        printf("%s", "hello");
        one();
        return 0;
    }
    
    int oneTwoThree() {
        oneTwo();
        return 0;   
    }
    
    int oneTwoThreeFour() {
        oneTwoThree();
        return 0;   
    }
    
    int main() {
    
        return 0;
    }
    

    文件two.c

    #include <stdio.h>
    
    int two() {
        return 0; 
    }
    
    int twoThree() {
        two();
        return 0;
    }   
    
    int twoThreeFour() {
        twoThree();
        return 0;    
    }   
    

    输出

    文件one.c

    #include <stdio.h>
    
    int one(); 
    int one_two(); 
    int one_two_three(); 
    int one_two_three_four(); 
    
    int one() {
        puts("");
        return 0;   
    }
    
    int one_two() {
        printf("%s", "hello");
        one();
        return 0;   
    }
    
    int one_two_three() {
        one_two();
        return 0;   
    }
    
    int one_two_three_four() {
        one_two_three();
        return 0;   
    }
    
    int main() {
    
        return 0;
    }
    

    文件two.c

    #include <stdio.h>
    
    int two() {
        return 0;  
    }
    
    int two_three() {
        two();
        return 0;
    }   
    
    int two_three_four() {
        two_three();
        return 0;    
    }  
    

    【讨论】:

      猜你喜欢
      • 2021-07-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-02-10
      • 2020-12-08
      • 1970-01-01
      相关资源
      最近更新 更多