【问题标题】:Regex: Replacing a string in a sub-string only正则表达式:仅替换子字符串中的字符串
【发布时间】:2023-03-13 19:58:02
【问题描述】:

我有特殊的文件格式,我需要替换几十个字符串并重新格式化其结构。作为最简单的解决方案,我准备了我的模式文件,其中存储了所有正则表达式定义/替换(约 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/\1X/g;
s/(.*?;.*)A(.*?;)/\1X\2/g;  # alternative to find the last A

但这会替换第一个 A。我可以有多个这样的模式来重复搜索和替换过程,但这听起来不是一个好的解决方案,因为我不知道子字符串中有多少个 A。

我尝试使用lookbehind,但没有成功。请注意,我只需要一个可以在我的模式文件中使用的正则表达式定义(即没有 perl 代码)。或者,我可以使用sedawk 来处理这种情况,但我不太熟悉。

感谢社区!

正则表达式101:https://regex101.com/r/Ic4ciA/1

【问题讨论】:

  • 您是否仅限于sedawk,或者是否有可以在这里使用的编程语言?
  • 这个替换过程只是我的bash 脚本中的操作之一,所以我可以对管道执行任何简单的命令。我想我可以使用一些代码来处理这个问题(我对python 非常熟悉)。但我更好奇是否可以用一些特殊的正则表达式模式匹配和替换字符串。

标签: regex regexp-replace


【解决方案1】:

perl one 班轮:

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

Demo

【讨论】:

  • 哇,这太棒了!非常实用,除此之外,我还学到了很多新东西——非捕获组,\G\K。非常感谢,托托!
【解决方案2】:

我不知道单独使用正则表达式工具一次性完成此操作的干净方法。但是,如果您愿意采用更迭代的方法,则可以很容易地用任何脚本语言处理它。这是一个完成工作的 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。最后,联合起来产生你想要的输出。

【讨论】:

  • 是的,这正是我的“备份”解决方案,即分解线路,替换其子字符串中所需的字符串,然后将部分连接回来。无论如何,谢谢。
  • 我喜欢您的备份解决方案胜过任何替代方案。问题是,您甚至不需要这里的正则表达式来进行替换,而单独的正则表达式并不是解析/迭代工具。即使使用编程语言,您仍然需要迭代以获得您想要的行为。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-04-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-02-04
相关资源
最近更新 更多