PHP preg_replace:查找不以感叹号开头的字符串部分

PHP preg_replace:查找不以感叹号开头的字符串部分,php,regex,preg-replace,Php,Regex,Preg Replace,我正在处理一些非常凌乱的Excel表格,并试图使用PHP来寻找线索 我有一个MySQL数据库,其中包含excel文档中的所有公式,像往常一样,当前工作表中的单元格名称前面没有“sheetname!”。为了使其可搜索(并在公式中查找死路径),我喜欢将数据库中的所有公式替换为它们的sheetname作为前缀 例如: =+(sheet_factory_costs!A17/sheet_employees!D23)+T12+W12 数据库包含当前工作表的名称,我想用该工作表名称更改上面的公式(我们称之为

我正在处理一些非常凌乱的Excel表格,并试图使用PHP来寻找线索

我有一个MySQL数据库,其中包含excel文档中的所有公式,像往常一样,当前工作表中的单元格名称前面没有“sheetname!”。为了使其可搜索(并在公式中查找死路径),我喜欢将数据库中的所有公式替换为它们的sheetname作为前缀

例如:

=+(sheet_factory_costs!A17/sheet_employees!D23)+T12+W12
数据库包含当前工作表的名称,我想用该工作表名称更改上面的公式(我们称之为“sheet_营业额”)

我使用preg_replace在PHP中进行了尝试,我认为我需要以下规则:

  • 找到一个或两个字母,后跟一个数字。这始终是公式中的单元格地址
  • 当有一天!在前面的位置上,已经有一个sheetname。所以我只寻找字母和数字,而不是以感叹号开头
  • 问题似乎是这个!也是模式中的一个特殊符号。即使我试图逃避它,它也不起作用:

    $newformula = 
    preg_replace('/(?<\!)[A-Z]{1,2}[0-9]/', 
    'lala', 
    $oldformula);
    
    $newformula=
    
    preg_replace('/(?您的负回溯已损坏,您需要将其定义为
    (?)。但是,您还需要在其前面使用单词边界,或使用
    (?回溯以确保
    [a-Z]{1,2}
    前面没有其他字母

    因此,您可以使用

    '~\b(?<!!)[A-Z]{1,2}[0-9]~'
    


    这里,
    \w+![A-Z]{1,2}[0-9](*SKIP)(*F)
    部分匹配1个或多个单词字符,然后是1个或2个大写ASCII字母,然后是一个数字,
    (*SKIP)(*F)
    将忽略匹配项,并使引擎在上一次匹配结束后继续查找匹配项。

    您的负回溯已损坏,您需要将其定义为
    (?)。但是,您还需要在其前面使用单词边界,或使用
    (?回溯以确保
    [a-Z]前面没有其他字母){1,2}

    因此,您可以使用

    '~\b(?<!!)[A-Z]{1,2}[0-9]~'
    


    这里,
    \w+![A-Z]{1,2}[0-9](*SKIP)(*F)
    部分匹配1个或多个单词字符,然后是1个或2个大写ASCII字母,然后是一个数字,
    (*SKIP)(*F)
    将忽略匹配,并使引擎在上一次匹配结束后继续查找匹配项。

    您需要将反斜杠加倍,因为它在字符串文字中具有转义含义,即“吃”它们。实际上,
    (?您需要将反斜杠加倍,因为它在字符串文字中具有转义含义,即“吃”他们。实际上,
    (?那个双感叹号起了作用。我不明白为什么我必须这样做,但效果很好。有/b和没有/b的结果没有区别。没有/b它不会影响前面的单词(sheetname):旧的:=+D16+(P25/(O25*(Entry_machines!C12)))新的:=+lala6+(la5/(lala5*(Entry_machines!C12))@TwomuchTime我宁愿你把它当作
    内部的
    (?(反向查找)构造。然后,它变得非常清楚。@TwomuchTime如果列名中有两个字母,
    \b
    会有所不同。试试
    +D16+(P25/(O25*(Entry_machines!CC12)))
    那个双感叹号起了作用。我不明白为什么我必须这样做,但效果很好。有没有/b,结果没有差别。没有/b,它不会影响前面的单词(sheetname):旧的:=+D16+(P25/(O25*(Entry_machines!C12)))新的:=+lala6+(lala5/(La5*(Entry_machines!C12)))@两次我宁愿你把它当作
    内部的
    (?(负向后看)构造。然后,它就变得非常清楚了。@两次如果列名中有两个字母,
    \b
    会有所不同。试试
    +D16+(P25/(O25*(Entry\u machines!CC12))
    '~\w+![A-Z]{1,2}[0-9](*SKIP)(*F)|\b[A-Z]{1,2}[0-9]~'