PHP PCRE匹配文本的“块”

时间:2012-11-16 01:07:56

标签: php regex

我有一个PHP应用程序,它应该解析上传的文本文件,其格式类似于:

|                  |                |                  |
| -----------------------------------------------------|
| Sample           | Data           |                  |
| -----------------------------------------------------|
| Sample           | Data           |                  |
| -----------------------------------------------------|
| Sample           | Data           |                  |
| -----------------------------------------------------|


| Accepts                    |                            |
| --------------------------------------------------------|
| All                        | Yes                        |
| --------------------------------------------------------|
| More                       | Yes                        |
| --------------------------------------------------------|


|            |            | Years      |            |            |
| ---------------------------------------------------------------|
| 1998       | 1999       | 2000       | 2001       | 2002       |
| ---------------------------------------------------------------|
| 2003       | 2004       | 2005       | 2006       | 2007       |
| ---------------------------------------------------------------|
| 2008       | 2009       | 2010       | 2011       | 2012       |
| ---------------------------------------------------------------|

我需要做的是基本上以相同的顺序隔离每个“块”,这样我就可以逐个循环它们。一个“解决方案”可能正在做

preg_split("/\n{4,}/", $text);

但是,如果提交文本的人认为不必要的换行不属于并删除它们,则会产生未完成的结果。我尝试过使用preg_match_all(),但是自从我做了任何真正的正则表达式以来已经有好几年了,所以我无法想出一个可用的解决方案。

“块”的第一行始终包含|和空格,但字段可能包含文本。 “块”的最后一行始终是一个后跟空格的管道,用短划线填充行,以|。结尾。

3 个答案:

答案 0 :(得分:0)

要匹配可选换行符,请尝试使用'/\n(\n{1,})?/'。这与第一个换行符匹配,然后匹配任何其他行(如果存在)。

考虑到这一点,你的答案是:

preg_split("/\n(\n{1,})?/", $text)

这将按换行符分割文本。

答案 1 :(得分:0)

您的问题无法解决,因为您没有可靠的方法来区分块的法线和块的第一行或最后一行。

我全都是robustness principle,但这是你必须训练用户不要破坏数据的情况之一。您无法接受来自任意删除逗号的用户的CSV格式数据,而且这里的情况基本相同。

答案 2 :(得分:0)

如果这是文本文件内容的样子,我会写一些类似

的内容
$pat = '~
    (?<=^|\r{3}|\n{3}|(\r\n){3})    # beginning of string or following 3 newline chars
        \|[ ]                       # a pipe and a space
        (
            [ \S]+                      # 1 or more space or non space char
            \|                          # a pipe
        )+                          # 1 or more of this group

        (\n|\r\n?)                  # a newline
        \|[ ]-+\|                   # a pipe, a space, multiple dashes and a pipe
        (\n|\r\n?)                  # a newline
        .*?                         # anything between newlines above and below
        (\n|\r\n?)                  # a newline
        \|[ ]-+\|                   # a pipe, a space, multiple dashes and a pipe
    (?=$|\r{3}|\n{3}|(\r\n){3})     # end of string or followed by 3 newline chars
~sx';
preg_match_all($pat,$str,$res);
$blocks = $res[0];
print_r($blocks);

我不确定这是否是最优雅甚至可靠的方式,因为很难猜出内容的确切含义。