PHP preg_replace: 查找不以感叹号开头的字符串部分
PHP preg_replace: find string part not starting with an exclamation point
我正在处理一些非常混乱的 Excel sheets,并试图使用 PHP 寻找线索..
我有一个 MySQL 数据库,其中包含 excel 文档中的所有公式,并且像往常一样,当前 sheet 中的单元格名称没有 "sheetname!"它的前面。为了使其可搜索(并在公式中找到死路),我喜欢用 sheetname 作为前缀替换数据库中的所有公式。
示例:
=+(sheet_factory_costs!A17/sheet_employees!D23)+T12+W12
数据库包含当前 sheet 的名称,我想用 sheet 名称更改上面的公式(我们称之为 "sheet_turnover")。
=+(sheet_factory_costs!A17 / sheet_employees!D23)+sheet_turnover!T12+sheet_turnover!W12
我在 PHP 中尝试使用 preg_replace,我想我需要以下规则:
- 找到一个或两个字母,紧跟一个数字。这始终是公式中的单元格地址。
- 当有!在之前的位置上,已经有一个sheet名称。所以我只查找不以感叹号开头的字母和数字。
问题似乎是!也是模式中的特殊符号。即使我试图逃避它,它也不起作用:
$newformula =
preg_replace('/(?<\!)[A-Z]{1,2}[0-9]/',
'lala',
$oldformula);
(lala 是我的临时标记,用于查看它是否选择了正确的单元格地址)
(是的,lala 仅位于第一个数字之上,但现在这不是问题)
(是的,所有 Excel $..$..(永久)标记都已被替换。无需在公式中构建它)
您的负向回顾已损坏,您需要将其定义为 (?<!!)
。但是,您还需要在它之前使用单词边界,或者使用 (?<![A-Z])
后视以确保在 [A-Z]{1,2}
.
之前没有其他字母
所以,您可以使用
'~\b(?<!!)[A-Z]{1,2}[0-9]~'
见regex demo。替换为 sheet_turnover![=15=]
,其中 [=16=]
是整个匹配值。
详情
\b
- 单词边界(这是必要的,否则 name!AA11
仍会匹配)
(?<!!)
- 没有!
紧靠当前位置 的左侧
[A-Z]{1,2}
- 1 或 2 个字母
[0-9]
- 一个数字。
另一种方法是匹配并跳过 "wrong" 上下文,然后匹配并保留 "right" 上下文:
'~\w+![A-Z]{1,2}[0-9](*SKIP)(*F)|\b[A-Z]{1,2}[0-9]~'
参见 this regex demo。
此处,\w+![A-Z]{1,2}[0-9](*SKIP)(*F)|
部分匹配 1 个或多个字符,然后是 1 或 2 个大写 ASCII 字母,然后是数字,(*SKIP)(*F)
将忽略匹配并使引擎继续查找上一场比赛结束后的比赛。
我正在处理一些非常混乱的 Excel sheets,并试图使用 PHP 寻找线索..
我有一个 MySQL 数据库,其中包含 excel 文档中的所有公式,并且像往常一样,当前 sheet 中的单元格名称没有 "sheetname!"它的前面。为了使其可搜索(并在公式中找到死路),我喜欢用 sheetname 作为前缀替换数据库中的所有公式。
示例:
=+(sheet_factory_costs!A17/sheet_employees!D23)+T12+W12
数据库包含当前 sheet 的名称,我想用 sheet 名称更改上面的公式(我们称之为 "sheet_turnover")。
=+(sheet_factory_costs!A17 / sheet_employees!D23)+sheet_turnover!T12+sheet_turnover!W12
我在 PHP 中尝试使用 preg_replace,我想我需要以下规则:
- 找到一个或两个字母,紧跟一个数字。这始终是公式中的单元格地址。
- 当有!在之前的位置上,已经有一个sheet名称。所以我只查找不以感叹号开头的字母和数字。
问题似乎是!也是模式中的特殊符号。即使我试图逃避它,它也不起作用:
$newformula =
preg_replace('/(?<\!)[A-Z]{1,2}[0-9]/',
'lala',
$oldformula);
(lala 是我的临时标记,用于查看它是否选择了正确的单元格地址)
(是的,lala 仅位于第一个数字之上,但现在这不是问题)
(是的,所有 Excel $..$..(永久)标记都已被替换。无需在公式中构建它)
您的负向回顾已损坏,您需要将其定义为 (?<!!)
。但是,您还需要在它之前使用单词边界,或者使用 (?<![A-Z])
后视以确保在 [A-Z]{1,2}
.
所以,您可以使用
'~\b(?<!!)[A-Z]{1,2}[0-9]~'
见regex demo。替换为 sheet_turnover![=15=]
,其中 [=16=]
是整个匹配值。
详情
\b
- 单词边界(这是必要的,否则name!AA11
仍会匹配)(?<!!)
- 没有!
紧靠当前位置 的左侧
[A-Z]{1,2}
- 1 或 2 个字母[0-9]
- 一个数字。
另一种方法是匹配并跳过 "wrong" 上下文,然后匹配并保留 "right" 上下文:
'~\w+![A-Z]{1,2}[0-9](*SKIP)(*F)|\b[A-Z]{1,2}[0-9]~'
参见 this regex demo。
此处,\w+![A-Z]{1,2}[0-9](*SKIP)(*F)|
部分匹配 1 个或多个字符,然后是 1 或 2 个大写 ASCII 字母,然后是数字,(*SKIP)(*F)
将忽略匹配并使引擎继续查找上一场比赛结束后的比赛。