正则表达式:仅替换子字符串中的字符串
Regex: Replacing a string in a sub-string only
我有特殊的文件格式,我需要替换几十个字符串并重新格式化其结构。作为最简单的解决方案,我准备了我的模式文件,其中存储了所有正则表达式 definitions/replacements(~100 个替换)。我正在使用 perl 查找和替换模式 (perl -p patterns source.file
)。到目前为止一切都很好。
但是,有一种情况我无法使用正则表达式解决。我需要替换整行的部分字符串,即仅替换子字符串中的字符串。
示例:为了简单起见,我只需要将中间字符串中的所有"A"替换为"X"(以;分隔)。
输入行:
ABCD ABCD; ABCD ABCD; ABCD ABCD
预期输出:
ABCD ABCD; XBCD XBCD; ABCD ABCD
^ ^
the only replaced characters
这将正确替换所有字符:
s/A/X/g;
但我只需要替换中间字段中的逗号。我试过了:
s/(.*?;.*?)A/X/g;
s/(.*?;.*)A(.*?;)/X/g; # alternative to find the last A
但是这会替换第一个 A。我可以有多个像这样的模式来重复搜索和替换过程,但这听起来不是一个好的解决方案,因为我不知道子中会有多少个 A字符串.
我尝试玩 lookbehind 但没有成功。请注意,我只需要一个可以在我的模式文件中使用的正则表达式定义(即没有 perl 代码)。或者,我可以使用 sed
或 awk
来处理这种情况,但我不太熟悉它。
感谢社区!
Regex101: https://regex101.com/r/Ic4ciA/1
我不知道有什么干净的方法可以单独使用正则表达式工具一次完成此操作。但是,如果您愿意接受一种更具迭代性的方法,那么使用任何脚本语言都可以相当轻松地处理它。这是完成工作的 Python 脚本:
inp = "ABCD ABCD; ABCD ABCD; ABCD ABCD"
parts = inp.split(';')
index = 1
while index < len(parts)-1:
parts[index] = parts[index].replace('A', 'X')
index += 1
output = ';'.join(parts)
print(output)
这会打印:
ABCD ABCD; XBCD XBCD; ABCD ABCD
方法是在分号处拆分输入字符串,生成术语列表。然后,从第二个到倒数第二个术语进行迭代,将字母 A
替换为 X
。最后,拼凑出你想要的输出。
一个 perl 一行:
echo 'ABCD ABCD; ABCD ABCD; ABCD ABCD' | perl -pe 's/(?:.+?;|\G).*?\KA(?=.*?;)/X/g'
ABCD ABCD; XBCD XBCD; ABCD ABCD
解释:
(?: # non capture group
.+? # 1 or more any character but newline, not greedy
; # semicolon
| # OR
\G # restart from last match position
) # end group
.*? # 0 or more any character but newline, not greedy
\K # forget all we have seen until this position
A # letter A
(?= # positive lookahead, make sure we have after:
.*? # 0 or more any character but newline, not greedy
; # a semicolon
) # end lookahead
我有特殊的文件格式,我需要替换几十个字符串并重新格式化其结构。作为最简单的解决方案,我准备了我的模式文件,其中存储了所有正则表达式 definitions/replacements(~100 个替换)。我正在使用 perl 查找和替换模式 (perl -p patterns source.file
)。到目前为止一切都很好。
但是,有一种情况我无法使用正则表达式解决。我需要替换整行的部分字符串,即仅替换子字符串中的字符串。
示例:为了简单起见,我只需要将中间字符串中的所有"A"替换为"X"(以;分隔)。
输入行:
ABCD ABCD; ABCD ABCD; ABCD ABCD
预期输出:
ABCD ABCD; XBCD XBCD; ABCD ABCD
^ ^
the only replaced characters
这将正确替换所有字符:
s/A/X/g;
但我只需要替换中间字段中的逗号。我试过了:
s/(.*?;.*?)A/X/g;
s/(.*?;.*)A(.*?;)/X/g; # alternative to find the last A
但是这会替换第一个 A。我可以有多个像这样的模式来重复搜索和替换过程,但这听起来不是一个好的解决方案,因为我不知道子中会有多少个 A字符串.
我尝试玩 lookbehind 但没有成功。请注意,我只需要一个可以在我的模式文件中使用的正则表达式定义(即没有 perl 代码)。或者,我可以使用 sed
或 awk
来处理这种情况,但我不太熟悉它。
感谢社区!
Regex101: https://regex101.com/r/Ic4ciA/1
我不知道有什么干净的方法可以单独使用正则表达式工具一次完成此操作。但是,如果您愿意接受一种更具迭代性的方法,那么使用任何脚本语言都可以相当轻松地处理它。这是完成工作的 Python 脚本:
inp = "ABCD ABCD; ABCD ABCD; ABCD ABCD"
parts = inp.split(';')
index = 1
while index < len(parts)-1:
parts[index] = parts[index].replace('A', 'X')
index += 1
output = ';'.join(parts)
print(output)
这会打印:
ABCD ABCD; XBCD XBCD; ABCD ABCD
方法是在分号处拆分输入字符串,生成术语列表。然后,从第二个到倒数第二个术语进行迭代,将字母 A
替换为 X
。最后,拼凑出你想要的输出。
一个 perl 一行:
echo 'ABCD ABCD; ABCD ABCD; ABCD ABCD' | perl -pe 's/(?:.+?;|\G).*?\KA(?=.*?;)/X/g'
ABCD ABCD; XBCD XBCD; ABCD ABCD
解释:
(?: # non capture group
.+? # 1 or more any character but newline, not greedy
; # semicolon
| # OR
\G # restart from last match position
) # end group
.*? # 0 or more any character but newline, not greedy
\K # forget all we have seen until this position
A # letter A
(?= # positive lookahead, make sure we have after:
.*? # 0 or more any character but newline, not greedy
; # a semicolon
) # end lookahead