使用perl从文件中删除#ifdef / #endif的出现

时间:2013-01-09 21:00:41

标签: xcode perl xcode4 xcode4.5

我有一个代码文件,在构建库后,我想在头文件中删除一些#ifdefs。我的第一个想法是将此作为XCode可以运行的perl脚本。虽然我当然可以打开头文件并将其中的所有内容读入perl中的字符串,但我很好奇以最佳方式执行以下操作

  1. 查找#ifdef EXAMPLE

  2. 的任何内容
  3. 删除它以及以下#endif

  4. 之间的任何内容

    所以示例是:

    int i;
    NSString *someString;
    #ifdef EXAMPLE
    NSString *exampleString;
    #endif
    bool done;
    

    ,输出为:

    int i;
    NSString *someString;
    bool done;
    

    我考虑的选项:

    • 查找每个#ifdef示例的索引并通过子字符串将其删除,并找到下一个#endif
    • 写一个可以某种方式删除这些出现的正则表达式。

    考虑到我之前没有写过Perl(Objective-C是我的主要语言),我很好奇是否有任何XCode或Perl开发人员对最佳方法有什么建议

3 个答案:

答案 0 :(得分:4)

我不确定你为什么要剥离ifdef,你可以使用C预处理器来做这个,但是这里你是如何在Perl中做的,因为这意味着我可以玩翻盖-flop operator。

首先要制作足够的正则表达式来匹配ifdef。 IIRC它们可以缩进,#和单词之间可以有缩进。

#ifdef
#    ifdef
    #ifdef

不确定最后一个是否有效,但无论如何我都会使用它。

my $ifdef_re = qr{^\s*#\s*ifdef\b};
my $endif_re = qr{^\s*#\s*endif\b};

如果仅删除#ifdef#endif之间的文字,则Perl使用的内容很少flip flop scalar .. operator

#!/usr/bin/env perl

use strict;
use warnings;

my $ifdef_re = qr{^\s*#\s*ifdef\b};
my $endif_re = qr{^\s*#\s*endif\b};

while(<DATA>) {
    my $in_ifdef = /$ifdef_re/ .. /$endif_re/;

    print if !$in_ifdef;
}

__DATA__
int i;
NSString *someString;
#ifdef EXAMPLE
NSString *exampleString;
#endif
bool done;

但是既然我们需要担心嵌套的ifdef,那就不够了。深度计数器负责处理。

#!/usr/bin/env perl

use strict;
use warnings;

my $ifdef_re = qr{^\s*#\s*ifdef\b};
my $endif_re = qr{^\s*#\s*endif\b};

my $ifdef_count = 0;
while(<DATA>) {
    $ifdef_count++ if /$ifdef_re/;

    print if $ifdef_count <= 0;

    $ifdef_count-- if /$endif_re/;
}

__DATA__
int i;
NSString *someString;
#ifdef EXAMPLE
NSString *exampleString;
#    ifdef FOO
this should not appear
#    endif
nor should this
#endif
bool done;

答案 1 :(得分:1)

我喜欢正则表达式,但是对于这个问题,我不会使用正则表达式,我只是逐行阅读,跟踪我是否在ifdef中:

my $nesting = 0;
while (<STDIN>)
   {
   $nesting += 1 if /^#ifdef/;
   print $_ unless $nesting;
   $nesting -= 1 if /^#endif/;
   }

如果您真的想使用正则表达式,并且已将整个文件读入变量$source,我认为如果您不需要担心嵌套,这将有效:

$source =~ s/^#ifdef.*?^#endif.*?$//gms;

^个字符将表达式的那些部分锚定到一行的开头。 $使得匹配的最后部分仅发生在一行的末尾。

.*?的行为几乎与.*相似,它匹配零个或多个字符,但它只进行最小匹配。因此,它不是一直匹配到最后一个#endif,而是与第一个匹配。

最后的/gms使其成为:

  1. 替换每一个事件,而不仅仅是一个(那是g)
  2. 在行边界处创建^​​和$匹配,而不仅仅是字符串边界(m)
  3. 制作。匹配换行符(s)
  4. 您可能希望将#ifdef#endif\s一起关注,只有在该字符串后面有空格时才会匹配。

答案 2 :(得分:0)

我只是使用unifdef执行此操作。 XCode默认安装:

-U will remove #ifdef and matching #else/#endif as if <constant> is undefined.
-D will remove #ifdef and matching #else/#endif as if <constant> is defined.

以下是一个例子:

$ cat test.h
#ifdef TEST

#ifdef DEBUG
# define AWESOME_DEBUG_LEVEL 1
#else
# define AWESOME_DEBUG_LEVEL 0
#endif

#endif

$ unifdef -U DEBUG test.h
#ifdef TEST

# define AWESOME_DEBUG_LEVEL 0

#endif

$ unifdef -U DEBUG -D TEST test.h

# define AWESOME_DEBUG_LEVEL 0