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

时间:2015-07-14 10:27:16

标签: php regex parsing ini

我在解析.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);解析此字符串时,它返回false或仅返回Description的第一行。 E. g。

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

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

不幸的是,有时钥匙会在空行后开始,有时则不行。值中可以包含空行(请查看Description中的Section2)。

所以问题是,如何使用parse_ini_string修改/清除此字符串?

1 个答案:

答案 0 :(得分:3)

您可以使用此模式描述多行键/值:

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

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

$content = preg_replace('~^\w+=\K\N*(?:\R++(?!\w+=|[[#;])\N+)+~m', '"$0"', $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"

此模式仅定位多行值,其他值保持不加引号。

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

如果某行中的任何地方都允许发表评论,请将\N更改为[^#\r\n]

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

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

模式匹配连续换行符字符组,后跟一个非空行,逐个替换连续换行符。

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