PHP 使用换行符解析 .ini 文件问题/需要正则表达式?

PHP parse .ini file problems with newlines / need regex?

我在解析 .ini 文件时遇到了一些问题,这些文件的值没有用引号引起来并且其中有一些换行符。这是一个例子:

[Section1]
ID=xyz

# A comment
Foo=BAR

Description=Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod
 tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,
 quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo
 consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse
 cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non
 proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
Screenshot=url-goes-here.png
Categories=some,categories

Vendor=abc

[Section2]
Description=Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod
 tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,
 quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo
 consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse
 cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non
 proident, sunt in culpa qui officia deserunt mollit anim id est laborum.

 Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod
 tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,

 quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo
 consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse
 cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non
 proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
Somekey=somevalue

当我尝试用 parse_ini_string($file_content, true, INI_SCANNER_RAW); 解析这个字符串时,它 returns 要么是假的,要么 returns 只是 Description 的第一行。例如

["Description"]=> "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod" // next lines are missing

我已经尝试删除换行符并将值括在引号中,但找不到有效的正则表达式。我需要一个匹配每个 key/value 直到下一个 key/value 或直到评论开始的模式。

不幸的是,有时键在空行之后开始,有时不是。值中可以有空行(查看 Section2 中的 Description)。

所以问题是,如何 modify/cleanup 这个字符串可以用 parse_ini_string 读取?

您可以使用此模式描述多行 key/value:

/^\w+=\N*(?:\R++(?!\w+=|[[#;])\N+)+/m

INI_SCANNER_NORMAL 默认选项允许在引号之间包含多行值,因此您只需添加引号即可:

$content = preg_replace('~^\w+=\K\N*(?:\R++(?!\w+=|[[#;])\N+)+~m', '"[=11=]"', $content);

图案详情:

~                  # pattern delimiter
^                  # start of the line
\w+                # key name
=
\K                 # discards characters on the left from the match result
\N*                # zero or more characters except newlines
(?:                # non-capturing group: eventual empty lines until a non empty line
    \R++           # one or more newlines
    (?!\w+=|[[#;]) # not followed by another key/value, a section or a comment
    \N+            # one or more characters except newlines
)+                 # at least one occurence
~m                 # switch on the multiline mode, ^ means "start of the line"

此模式仅针对多行值,其他值不加引号。

注意:我假设每个键、注释、部分都从一行的开头开始。如果不是这种情况,例如前导 spaces,您可以轻松调整在每个换行符后添加 \h*+ 的模式。

如果一行中的任何地方都允许注释,请将 \N 更改为 [^#\r\n]


如果您想使用 INI_SCANNER_RAW 选项,您必须删除值中的换行符:

$pattern = '~(?:\G(?!\A)|^\w+=[^#\r\n]*)\K\R++(?!\w+=|[[#])([^#\r\n]+)~';
$content = preg_replace($pattern, ' ', $content);

该模式逐个匹配后跟非空行的连续换行符组,并用 space.

替换连续换行符

另一种方法是使用第一个模式,但这次使用 preg_replace_callback 在回调函数中执行简单的字符转换。请注意,如果您想转义特殊或有问题的字符,这种方式可能会很有趣。