我有一个包含以下文本之一的字符串:

  • 内联;文件名=“名称。扩展名”;
  • 内联;文件名="name.extension"
  • 内联;文件名='name.extension';
  • 内联;文件名='name.extension'
  • 内联;文件名=名称。扩展名;
  • 内联;文件名=名称.extension

  • 我想提取 name.extension 并且可以处理前 5 种情况,但我无法弄清楚如何使用单个正则表达式处理所有情况。我尝试过的一切都变得太贪婪了。这甚至可能吗?

    适用于前 5 个的正则表达式是:
    /filename=["']?(.*)(?=["']?;)/
    

    name.extension 位于第一个捕获组中,并且必须允许 linux 中文件名的任何有效字符。这包括 ' 和 "和 ; 在其中。

    谢谢你的帮助!

    最佳答案

    分三个阶段做。

  • ; 上拆分以分离语句。
  • = 上拆分键/值对。
  • 处理引用值。

  • 这是一个基本的例子。
    def get_value(line)
        # Split into statements
        statements = line.split(/\s*;\s*/)
    
        # Extract the value of the 2nd statement
        _,value = statements[1].split(/\s*=\s*/)
    
        # Strip the quotes
        value.gsub!(/^(['"]?)(.*)\1$/, '\2')
    
        return value
    end
    

    有一些边缘情况无法处理:如果您感兴趣的语句不是第二个怎么办?但这可以根据需要修复。当它分多个步骤完成而不是试图将它塞进一个正则表达式时,改进解析要容易得多。

    例如,这可以正确处理嵌入和转义的引号,如 %q[inline; filename="name's.extension"]%q[inline; filename="name's.\\"extension\\""]

    如果你真的想把它作为一个单一的正则表达式来做,好吧,你要求它。
    re = /
        \bfilename
        \s*=\s*
        (?:
            (?<quote>['"])(?<value>.*)\k<quote> |
            (?<value>[^;]+)
        )
    /x
    return re.match(line)['value']
    

    这将扩展的处理分为两种选择:一种带引号,一种不带。否则 filename=name.ext; 将拿起分号,我想不出另一种不会引入新问题的方法来阻止它。

    例如, /\bfilename\s*=\s*(?<quote>['"]?)(?<value>.*?)\k<quote>;?$/ 将在测试数据上工作,但如果分号后有任何类似 %q[inline; filename='name.extension'; foo] 的内容,它将失败。

    您要求专业的正则表达式知识。成为正则表达式专家的一部分就是知道什么时候不应该使用正则表达式。这可能应该使用语法来处理,否则您将不断追逐边缘情况。

    关于ruby - 提取带有和不带有终止字符的文件名,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/42355668/

    10-13 07:45
    查看更多