【问题标题】:PHP parse .ini file problems with newlines / need regex?PHP用换行符解析.ini文件问题/需要正则表达式?
【发布时间】:2015-10-02 22:32:24
【问题描述】:

我在解析 .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 读取?

【问题讨论】:

  • 如果您的多行字符串被引用,似乎可以正常工作 - ideone.com/JUvA7D
  • .ini 格式在这里似乎不是正确的格式选择。您是否考虑过使用允许数据包含换行符的文件格式,例如 JSON?
  • @Simba 我个人会使用 JSON,但在这种情况下,格式不是我的选择。

标签: php regex parsing ini


【解决方案1】:

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

/^\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*+ 的模式。

如果一行中的任何位置都允许使用 cmets,请将 \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 在回调函数中执行简单的字符转换。请注意,如果您想转义特殊或有问题的字符,这种方式可能会很有趣。

【讨论】:

  • @Jonny5:确实,INI_SCANNER_RAW 选项会导致带有多行引用值的解析错误。您必须使用默认选项INI_SCANNER_NORMAL。要使用 INI_SCANNER_RAW 选项,您必须删除所有换行符(在这种情况下无需添加引号),但这样您会失去“文本布局”。
  • 我只是found this at php.net #51094 ...The ;即使在原始模式下仍然是评论。所有其他字符都被认为只是字符...意味着如果我理解正确(also read #55091 at grokbase.com),引号被视为带有INI_SCANNER_RAW的“只是字符”。
  • @Jonny5: 有趣,不幸的是我无法重现这个特定于 php 5.3 的错误,我不再使用这个版本。
  • 太好了,正是我需要的。谢谢!
猜你喜欢
  • 2021-04-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-09-11
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多