【问题标题】:Regex: using dot all flag, how to prefix each line?正则表达式:使用点所有标志,如何为每一行添加前缀?
【发布时间】:2013-11-29 12:59:33
【问题描述】:

为每一行添加前缀的正确正则表达式是什么?

假设我有输入数据:

SOME OTHER DATA

TABLE
ROW
ROW
ROW
END

SOME OTHER DATA

我只对 TABLE 和 END 之间的内容感兴趣。

在 php 中,您可以编写如下 /TABLE.*?END/s 之类的正则表达式,它将第一次出现的 TABLE 匹配到第一次出现的 END。但是有没有办法可以在每行前面加上 %?所以结果会变成:

SOME OTHER DATA

%TABLE
%ROW
%ROW
%ROW
%END

SOME OTHER DATA

感谢任何帮助。

【问题讨论】:

  • 最简单最直接的方法是使用两个表达式。
  • 您介意提供一个例子吗?
  • 输入数据是一行还是数组?

标签: php regex


【解决方案1】:

你可以用一个替换来做到这一点:

$txt = preg_replace('~^(?:TABLE\R|\G(?!\A)(?:END$|.+\R|.+\z))~m', '%$0', $txt);

请注意,此模式假定始终有一个结束 END“标签”。如果不是这种情况,替换将一直持续到空行(+ 量词的原因)或字符串结尾。

您还可以选择检查 TABLE 标记是否以 END 标记结束:

$pattern = '~^(?:TABLE\R(?=(?:.+\R)*?END$)|\G(?!\A)(?:END$|.+\R|.+\z))~m';

第一个模式细节:

^                   # matches the start of a line
(?:                 # open a non-capturing group
    TABLE \R        # TABLE and a newline (CR, LF or CRLF)
  |                 # OR
    \G (?!\A)       # contigous to a precedent match but not
                    # at the start of the string 
    (?:             #
        END $       # END at the end of a line
      |             #
        .+ \R       # a line (not empty) and a newline
      |             #
        .+ \z       # the last line of the string
    )               # close the non-capturing group
)                   #

其他前瞻细节:

(?=             # open the lookahead
    (?:.+\R)*?  # matches zero or more lines lazily
    END$        # until the line END
)

另一种方式

$arr = preg_split('/\R/', $txt);
$state = false;
foreach ($arr as &$line) {
    if ($state || $line === 'TABLE') {
        $state = ($line !== 'END');
        $line = '%' . $line;
    }
}
$txt = implode("\n", $arr);

此代码的行为与第一个模式相同,请注意,您获取的是一个带有 UNIX 格式换行符的字符串。

【讨论】:

    【解决方案2】:

    给你。我确实创建了一个正则表达式并为您正确评论它:

    /(?:
     #start by finding the initial position of the table start, in order to store the match position for \G
        TABLE\n\K|
        #after we've found the table head, continue matching using this position. make sure we arent at the beginning of the string
        \G(?<!^)
    )
    #capture the data we're interested in
    (?:
        #make sure there is no 'END' in the string
        (?!END)
        #match everything until the line ending
        .
    )*
    #consume the newline at the end of the string
    \n/x
    

    将结果替换为%$0

    在此处查看实际操作:http://regex101.com/r/rA5bV1

    --

    但是,如果您不了解我创建的正则表达式,我建议您使用替代方法。创建一个将捕获表内容的正则表达式,然后将 % 附加到每一行。使用以下表达式捕获内容:/TABLE\n((?:(?!END).)*)END/。我没有评论这个,你应该可以通过阅读其他表达式的cmets来弄清楚。

    【讨论】:

      【解决方案3】:

      您应该使用 2 个正则表达式:

      $txt = file_get_contents('input.txt');
      preg_match("#(.*(?<=TABLE\n))(.*\nEND)(.*)#ms",$txt,$m);
      $new = $m[1].preg_replace("#^#ms","%",$m[2]).$m[3];
      print $new;
      

      ms 修饰符使正则表达式表现得像整个文本是一行,而 \n 像普通字符一样与 . 匹配。

      如果您只想在一个正则表达式中执行此操作,则必须使用特殊匹配块,例如其中之一:

      希望对您有所帮助。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-04-30
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2023-02-03
        • 2015-03-21
        相关资源
        最近更新 更多