在平衡字符内搜索特定文本(递归

时间:2018-04-23 19:04:18

标签: c# regex visual-studio perl

鉴于以下(已消毒)输入:

Return_t
func()
{
  Type<SubType> cursorFeature(true);

  while (nDist < 800)
  {
    Result = Example(&var, 0, cursorFeature); //interested in this because inside loop, and not dereferenced or incremented
    if (!(++cursorFeature).NoMoreRecords())
    {
      if (!BLAH(blah)
        && (otherFunc(&var, &cursorFeature->derefenced, MACRO) != 0))
      {
        bIsChanged = true;
        break;
      }
      memcpy(&var, &cursorFeature->dereferenced, sizeof(anotherType_t));
    }
  }

  //more stuff
  }
}

我有以下正则表达式,用于捕获使用Type

后发生的循环
Type.*<.*>\s*(\w*)[^}]*?(?:while|for)\s*\(.*?\n?.*?(\{(?>[^{}]|(?-1))*\})

https://regex101.com/r/Kr0zQq/3

我还有以下正则表达式,用于捕获Type类型变量的特定用法:

Type.*<.*>\s*(\w*)[\s\S]*?\K(?<!\+\+)\1(?!->|\+\+)

https://regex101.com/r/Kr0zQq/4

我的目标是以某种方式将这些组合在一起,最好是 ONE 正则表达式(如果可能的话,我希望能够在VS内部进行搜索)。鉴于递归正则表达式的性质,我不确定这是不可能的......我怀疑它不是。如果没有,那么在搜索数百个文件时不会丢失文件名/数字上下文的聪明的东西会很棒。我基本上需要文件名和行号。上下文很棒,但不是必需的。

为了澄清,我想捕获cursorFeature,因为它的类型为Type,然后我想在"loop"{.....}

中搜索它的使用情况

编辑

关于我使用正则表达式解决此问题的说明。被搜索的代码超过一百万行,跨越由各种编译器编译并由多个构建系统构建的多个项目。例如,使用宏和高级语言功能意味着甚至VS Intellisense 经常错误地编写VS能够编译的代码。和YCM(vim)一样。因此,一个可能过于贪婪的正则表达式,即70%的误报是好的。 (由于缺少循环中变量使用的进一步发生,因为在那一点上通常很容易扫描其余部分。)然而,尝试使用“通用”PCRE作为单行程执行此操作可能是愚蠢的。 :)

3 个答案:

答案 0 :(得分:5)

您可以通过三个选项查看以下循环中是否存在匹配的变量名称。第一个是将(\1)添加到原子组并检查您的环境中是否存在此捕获组(如果可能的话):

(?>(\1)|[^{}]|(?-2))*

其次,你可以通过使用负向前瞻来缓和[^{}]的匹配过程:

(?>(?!\1)[^{}]|(?-1))*

但是如果你没有像我在评论中提供的演示中所做的那样选择右括号,它就会失败。

第三个更好的解决方法是使用动词(*ACCEPT),这会立即导致成功匹配的结束,而不会在正则表达式中进行进一步更改:

(?>(\1)(*ACCEPT)|[^{}]|(?-2))*

Live demo

答案 1 :(得分:1)

使用单个正则表达式执行此操作需要使用Perl代码块
和有条件的代码。

虽然接受的答案很好,但它无法验证Type变量
将存在于平衡循环内。

这里的代码只是存储Type变量的位置 在所有嵌套循环中找到。它不会错过任何一个。

作为一个例子,我在一些文件中为多个位置播种了数据集 循环,其他地方的单一位置,另一个没有。

除了字符串中的位置之外,你如何定位取决于你。

Perl

use strict;
use warnings;

$/ = undef;
my $data = <DATA>;

my @vals;

while ( $data =~ /

          (?{ @vals = () })             # Code block - Initialize @vals

          Type .* < .* > \s* 
          ( \w+ )                       # (1)
          [^}]*? 
          (?: while | for )
          \s* \( .*? 
          (?: \r? \n )?
          .*? 

          (?<core>                      # (2 start)
               \{
               (?>
                    (?<! \+\+ )
                    ( \1 )                        # (3)
                    (?! -> | \+\+ )
                    (?{
                         # Code block - Push capture position onto @vals
                         push (@vals, pos());
                    })
                 |  [^{}] 
                 |  (?&core) 
               )*
               \}
          )                             # (2 end)

          (?(?{
               # Code conditional - Fail this block (bypass) if didn't find any
               @vals == 0
            })
               (*SKIP) (*FAIL) 
          )
     /xg )
{
    print "\nfound   '$1'   at pos:   ";
    for ( @vals )
    {
        print $_ , ",  ";
    }
}

__DATA__


Return_t
func()
{
  Type<SubType> cursorFeature(true);

  while (nDist < 800)
  {
    Result1 = Example(&var, 0, cursorFeature);  
    if (!(++cursorFeature).NoMoreRecords())
    {
      if (!BLAH(blah)
        && (otherFunc(&var, &cursorFeature->derefenced, MACRO) != 0))
      {
        bIsChanged = true;
        Result2 = Example(&var, 0, cursorFeature);  
        break;
      }
      else
        Result3 = Example(&var, 0, cursorFeature);  

      memcpy(&var, &cursorFeature->dereferenced, sizeof(anotherType_t));
    }
  }

  //more stuff
  }

// ---------------------------------

Return_t
func()
{
  Type<SubType> globeFeature(true);

  while (nDist < 800)
  {
    if (!(++globeFeature).NoMoreRecords())
    {
      if (!BLAH(blah)
        && (otherFunc(&var, &penFeature->derefenced, MACRO) != 0))
      {
        bIsChanged = true;
        break;
      }
      else
      memcpy(&var, &globeFeature->dereferenced, sizeof(anotherType_t));
    }
  }
  }
} 

// ---------------------------------

Return_t
func()
{
  Type<SubType> penFeature(true);

  while (nDist < 800)
  {
    if (!(++penFeature).NoMoreRecords())
    {
      if (!BLAH(blah)
        && (otherFunc(&var, &penFeature->derefenced, MACRO) != 0))
      {
        bIsChanged = true;
        Result = Example(&var, 0, penFeature);  
        break;
      }
      else
      memcpy(&var, &penFeature->dereferenced, sizeof(anotherType_t));
    }
  }
  }
} 

输出

found   'cursorFeature'   at pos:   148,  378,  465,
found   'penFeature'   at pos:   1323,

答案 2 :(得分:1)

  

我的目标是以某种方式将这些结合起来,最好是合并到一个正则表达式中(如果可能的话,我希望能够在VS内部进行搜索)。

以下是使用 Dot-Net 正则表达式在VisualStudio IDE中执行此操作的方法。

这将产生误报 我认为VS将跨​​越输出窗口中的线条,这将使您能够 查看代码中的块,并在必要时查看数千个文件。

我在http://regexstorm.net/tester对此进行了测试,效果很好 无法创建永久链接,它说它太长了......

但你可以在regexstorm自己尝试一下。

(如果您在C#程序集中使用它,则可以获得Vars的全部(多个)  在捕获集合的循环中找到:CaptureCollection cc = Match.Groups["Vars"].Captures;
然后遍历cc。)

这是压缩的

Type.*<.*>\s*(\w+(?!\w))[^}]*?(?:while|for)\s*\(.*?(?:\r?\n)?.*?(?>\{(?>(?<!\+\+)(?<Vars>\1)(?!->|\+\+)|[^{}]|\{(?<Depth>)|\}(?<-Depth>))*(?(Depth)(?!))(?(Vars)|(?!))\})

可读版本

 Type .* < .* > \s* 
 (                             # Type variable to find in Loop
      \w+ 
      (?! \w )                      # Must be an entire word
 )
 [^}]*? 
 (?: while | for )             # While or for loop
 \s* \( .*? 
 (?: \r? \n )?
 .*? 

 (?>
      \{                            # Match opening {
      (?>                           # Then either match (possessively):
           (?<! \+\+ )                   # Not incrementing variable
           (?<Vars> \1 )                 # Collect the Variable                                                                                                   
           (?! -> | \+\+ )               # Not dereferencing or incrementing variable
        |                              # or
           [^{}]                         #   Anything (but only if we're not at the start of { or } )
        |                              # or
           \{                            #  { (and increase the braces counter)
           (?<Depth> )
        |                              # or
           \}                            #  } (and decrease the braces counter).
           (?<-Depth> )
      )*                            # Repeat as needed.
      (?(Depth)                     # Condition that the braces counter is at zero.
           (?!)                          # Fail if depth > 0
      )
      (?(Vars)                      # Condition that the Variables matched something
        |  (?!)                          # Fail if Vars stack is empty
      )
      \}                            # Then match a closing }. 
 )

祝你好运,让我们知道结果如何!