我的测试配置文件(test_config.conf)如下所示
[DEFAULT]
system_name=
#test
flag=true
我想阅读此内容并使用预期输出"system_name"
扫描密钥nil
的值。我可以使用配置解析器来读取内容,但使用scan
是我的要求。
我做了:
File.read
file_data.scan(/^#{each}\s*=\s*(?!.*#)\s*(.*)/)
^system_name\s*=\s*(?!.*#)\s*(.*)$
我使用(?!.*#)
来忽略以#
开头的值。
返回#test
。有人可以帮助我理解为什么会这样做,以及如何改变我的正则表达式以使其按预期工作?
答案 0 :(得分:1)
另一种情况是回溯如何混淆正则表达式用户。 (?!.*#)
否定前瞻必须与#
后未紧跟的位置匹配。由于前面的模式部分可以以各种方式匹配字符串,一旦失败,正则表达式引擎重试量化的子模式。因此,在您的情况下,\s*
匹配0个或更多的空格。一旦正则表达式引擎匹配=
之后的所有空格,它就会找到#
- 并失败。然后回溯:尝试匹配零空格。并且发现#
之后没有=
。并且成功。
使用\s*+
的占有量词来禁止回溯:
^system_name\s*=\s*+(?!#)(.*)$
^
请参阅Rubular demo。因此,在所有0+空格匹配后,前瞻只会运行一次。如果匹配不匹配,整场比赛将立即失败。
另一种方法是使用[^\s#]
否定字符类:
^system_name\s*=\s*([^\s#].*)$
^^^^^^^
查看另一个Rubular demo
此处,[^\s#]
仅匹配不是空格的字符,也不匹配#
,然后.*
将匹配除换行符之外的任何0 +字符。
根据评论中的反馈,输入的结构可能相当松散,而key = value可以跟在system_name
行之后。在这种情况下,您还需要确保您捕获的文本实际上并不是以=
符号后面的一些单词字符开头:
/^system_name\s*=\s*+(?!#|\w+=)(.*)$/
完整模式详情:
^
- 开始行system_name
- 文字子字符串\s*
- 0个或更多空格=
- 等号\s*+
- 0个或更多空格,由于*+
占有量词,没有回溯到模式中(?!#|\w+=)
- 如果在当前位置的右侧(即紧随其后)找到#
或1+个字符,然后=
,则表示匹配失败的否定前瞻0+空格)(.*)
- 第1组:直到行尾的任何0+字符$
- 行尾。