我在解析 .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
的第一行。例如
["Description"]=> "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod" // next lines are missing
我已经尝试删除换行符并将值括在引号中,但找不到有效的正则表达式。我需要一个匹配每个键/值的模式,直到下一个键/值或直到评论开始。
不幸的是,有时键在空行之后开始,有时不是。值中可以有空行(查看 Section2
中的 Description
)。
所以问题是,我如何修改/清理这个字符串,使其可以用 parse_ini_string
读取?
最佳答案
您可以使用此模式描述多行键/值:
/^\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
在回调函数中执行简单的字符转换。请注意,如果您想转义特殊或有问题的字符,这种方式可能会很有趣。
关于PHP 解析 .ini 文件问题与换行符/需要正则表达式?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31404066/