为什么`word(。(?!another-word))*?`只匹配一个字符?

时间:2017-03-27 12:19:41

标签: regex perl

我有一个字符串

 /*Unmanaged Struct*/
    struct Grid2D
        {
        double* getLx() const {
            return _Lx;
            }
        void setLx(double* val) {
            _Lx = val;
            }
        private:
            double* _Lx;
        public:
            int _count;
        };

    #pragma unmanaged
    void UnmanagedFillGrid(Grid2D& d)
        {
        printf_s("\nunmanaged");
        double* item = new double[d._count];
        int i = 0;
            while (i++ < d._count) {
                int r = (rand() % 100) + 1;
                item[i] = r;
                printf_s("array[%d] = %f\n", i, item[i]);
                }
            d.setLx(item);
        }

    #pragma managed  
    int main(array<System::String ^> ^args)
    {
        Grid2D d;
        d._count = 10;
        UnmanagedFillGrid(d);   
        Console::WriteLine("[managed] count = {0}", d._count);
        //getLx returns pointer to double, I need to get in double^
        //Is this possible ?
        double^ managedLx = d.getLx();//How to convert ?? 


        return 0;
    }

在本文中,我想在单词my $text = "abc " . "VVV foo III " . # <- here "pqr hash def " . "VVV bar hash baz III " . # <- here "stu hash ghi " . "VVV bbb, ccc hash ddd III " . # <- here "vwx"; hash之间替换单词VVV。替换的潜在片段在上面的代码段中标有III。第一个片段没有单词<- here,因此不能在那里进行替换。

我提出了以下正则表达式:

hash

使用此正则表达式,$text =~ s/ VVV (.(?!III))*? hash (.*?)(?=III)/ VVV $1 HASH $2/g; 变为

$text

替换是在正确的位置进行的,然而abc VVV foo III pqr hash def VVV r HASH baz III stu hash ghi VVV c HASH ddd III vwx 之前的文字仅替换为一个字符(hash而不是VVV r HASH和{ {1}}代替VVV bar HASH)。

我不明白为什么会这样。据我理解正则表达式,VVV c HASH应该充当锚点,从而确保匹配后的每个字符。

3 个答案:

答案 0 :(得分:4)

您正尝试在模式中使用tempered greedy token。要正确地编写它,您需要将前瞻放在之前的;#temp;&#34 ;,使用非捕获组来包装带有点的前瞻,并且捕获与另一个捕获组内的构造匹配的整个子串。

/VVV ((?:(?!III).)*?) hash (.*?III)/
     ^              ^

请注意,将III置于积极的预测中是没有意义的,您也可以匹配并捕获它以便稍后使用$2进行恢复。

现在,((?:(?!III).)*?)将捕获组1中的任何字符(除了换行符),0或更多次出现,尽可能少,不会启动III字符序列。

答案 1 :(得分:2)

因为:(.(?!III))*? - 星号位于括号内,而不是内部,因此您不会捕获所有出现的 - 只有一个。 (最后一个)。

评论中注明Wiktor Stribiżew

/VVV ((?:(?!III).)*?) hash (.*?)(?=III)/

你想做什么。

但是我建议你只是试图让你的正则表达式变得过于复杂,而你应该正在做的事情是进一步解决问题 - 多重匹配如果有必要得到包含;排除集。

类似的东西:

#!/usr/bin/env perl
use strict;
use warnings;

my $text = "abc " . 
  "VVV foo III " .                  # <- here
  "pqr hash def " . 
  "VVV bar hash baz III " .         # <- here
  "stu hash ghi " . 
  "VVV bbb, ccc hash ddd III " .    # <- here
  "vwx";

#split your block on VVV, without removal
for ( split /(?=VVV)/, $text ) {
   #replace 'this chunk' so between 'VVV' and 'III' 
   s/hash (.*) III/HASH $1 III/g;
   #print the line. Or you could insert this back into your primary text
   print;

}

答案 2 :(得分:2)

我会通过在空格上拆分字符串并迭代结果列表来完成此操作,使用范围运算符来确定任何给定的hash出现是否有资格进行更改

看起来像这样。请注意,split还会捕获插入的空白区域,以便可以替换标签或多个空格

use strict;
use warnings 'all';
use feature 'say';

my $text =
    "abc " .
    "VVV foo III " .                  # <- here
    "pqr hash def " .
    "VVV bar hash baz III " .         # <- here
    "stu hash ghi " .
    "VVV bbb, ccc hash ddd III " .    # <- here
    "vwx"
;

my @text = split /(\s+)/, $text;

for ( @text ) {
    my $in_range = $_ eq 'VVV' .. $_ eq 'III';
    $_ = 'HASH' if $_ eq 'hash' and $in_range;
}

say join '', @text;

输出

abc VVV foo III pqr hash def VVV bar HASH baz III stu hash ghi VVV bbb, ccc HASH ddd III vwx