【问题标题】:script to add namespace to c++ files将命名空间添加到 C++ 文件的脚本
【发布时间】:2011-10-31 20:58:16
【问题描述】:

所以我有一个庞大的代码库,需要添加一个命名空间。我没有手动执行此操作,而是考虑使用 grep、xargs 和 sed 将命名空间添加到所有源文件...

但我的技能达不到标准。 理想

namespace foo 
{

将在所有包含之后添加,并在 .h 文件中的 #endif 之后添加“}”。

对于 .cpp 文件,在所有包含之后添加“使用命名空间 foo”就足够了。

我一直在玩 sed,但还没有走多远。

任何帮助将不胜感激。谢谢!

【问题讨论】:

  • 我建议您使用像 Ruby 这样的脚本语言和正则表达式来完成这项工作。根据您的要求和一些 Ruby 示例的谷歌搜索,您可以在 30 分钟到 1 小时内完成此脚本。您可以使用rubular.com 来测试您的正则表达式。 FWIW,我刚刚编写了一个 Ruby 脚本来查找所有 .hpp 和 .cpp 文件之间的命名空间/模块依赖关系 - 使用正则表达式编写了大约一个小时。
  • sed 是早期的程序之一,它将正则表达式的使用作为其处理文本的主要工具。祝大家好运。

标签: c++ regex linux sed


【解决方案1】:

这不是一件容易的事。造成问题的因素包括

  • 您不想放在新命名空间中的内容,例如
    • 类似language "C" { C-stuff }的构造
    • 转发不属于您的类的声明。如果您使用一些不使用命名空间的外部包,这将变得困难 n 倍。
  • 即使找到放置namespace Foo { 和结束符“}”的位置也很困难。
    • 您确实想附上前向声明,不属于您的声明除外。
    • 您通常希望在文件范围内包含涉及一对大括号的任何内容 - 除了 language C 之类的内容。
    • 维护程序员(如果您的代码存在的时间足够长的话)会对您的代码做各种坏事。他们会在类或函数内、类和函数之间、除顶部之外的任何地方提出声明,以便于编写脚本。
    • 您不想将事物进行双重嵌套。这样做非常容易。
    • 出于各种原因,有些人将看似无关的内容放在标题的末尾。这可能是一个特别讨厌的问题。
    • 如果您决定尝试封装每个类、结构和枚举,您将不得不弄清楚声明的真正开始位置。你想包装template 声明,如果有的话,当然还有 doxygen cmets 等等。
    • 找到一个类的结尾可能是一件令人讨厌的事情。人们有这种讨厌的倾向,即在 cmets 和字符串中放置不匹配的大括号。

祝你好运!编写一个脚本需要半个多小时。与重写所有代码相比,这将花费更少的时间。我建议您使用比 sed 更强大的东西。 Perl、python 和 ruby​​ 是三个不错的选择。

【讨论】:

    【解决方案2】:

    这让我成功了一半:

    #!/bin/sh
    NAMESPACE=my_namespace
    for x in $(find . -name "*.h"); do
        sed -i "$(grep -n "^#" $x | tail -2 | head -1 | sed 's/:.*//')a\\\nnamespace $NAMESPACE {\n" $x
        sed -i "$(($(grep -n "^#" $x | tail -1 | sed 's/:.*//')-1))a} // namespace $NAMESPACE\n" $x
    done
    
    for x in $(find . -name "*.cpp"); do
        sed -i "$(grep -n "#include" $x | tail -1 | sed 's/:.*//')a\\\nnamespace $NAMESPACE {\n" $x
        echo >> $x
        echo "} // namespace $NAMESPACE" >> $x
    done
    

    它主要在 h 文件中定位最后一个预处理器指令,并在那里添加命名空间。它在最后一个预处理器指令之前关闭命名空间(我假设我的 h 文件末尾有一个#endif)。如果不是这种情况,可以相应地调整脚本。

    在 cpp 的情况下,我寻找最后一个包含来打开命名空间并在文件末尾关闭它。

    这远非完美,但面对 100 多个文件,这让工作变得轻松了很多。

    【讨论】:

      【解决方案3】:

      注意,这并没有考虑关闭守卫#endif 行,但是将它们包装在namespace {}; 中似乎没有任何伤害。

      根据您的喜好取消注释行。

      #!/usr/bin/env bash
      namespace="namespace m {"
      pad="    "
      
      function processFile {
          # dos2unix "$1"
          local fn=$1
          local tmp="$1.tmp"
          echo "Processing '$fn'"
          rm -f "$tmp"
          local -i skipping=1
          local regSkip="^(#include.*|#pragma.*|//.*|)"'$'
          local line
          while IFS= read -r line
          do
              if (( skipping )); then
                  if [[ $line =~ $regSkip ]]; then :
                  else skipping=0; echo "$namespace" >> "$tmp"
                  fi
                  echo "$line" >> "$tmp"
              else
                  echo "$pad$line" >> "$tmp"
              fi
          done < "$1"
          echo "$line" >> "$tmp"
          echo "};" >> "$tmp"
          mv -f "$fn" "$fn.ori"
          # optionally reformat
          astyle --options='e:\git\sfink.ini' < "$tmp" > "$fn" && rm "$tmp"
          # else just move
          # mv -f "$tmp" "$fn"
      }
      
      # for fn in $( find . -name '*.h' ); do processFile "$fn"; done
      # for fn in $( find . -name '*.cpp' ); do processFile "$fn"; done
      for fn in "$@"; do processFile "$fn"; done
      

      n.b.,文件必须是 unix 换行格式

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-01-02
        • 2012-07-05
        • 2011-11-27
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多