【问题标题】:Using Python to substitute or swap substrings in a file使用 Python 替换或交换文件中的子字符串
【发布时间】:2012-05-29 21:38:40
【问题描述】:

假设我在以下格式的 ASCII 文件中有一行:

{text1} {stringA} {text2} {stringB} {text3}

其中{stringA}{stringB} 是感兴趣的子字符串。我们分别称它们为“A”和“B”。字符串 {text1}{text2}{text3} 是不包含 A 或 B 的任意长度(可能为空)的字符串。

我想在 Python 中做的只是交换 A 和 B 以使该行从

{text1} {stringA} {text2} {stringB} {text3}

{text1} {stringB} {text2} {stringA} {text3}

如果能提供任何帮助,我将不胜感激。我认为通过在这个问题上获得帮助,它将帮助我学习更好地使用 Python 中的正则表达式。

请注意,{text1}{text2}{text3} 是未知字符串。

我们确切地知道子字符串 A 和 B。我们知道 A 在该行中位于 B 之前。但是,我们不知道它们之前/之间/之后是什么(如果有的话)。

示例(A=John,B=Tim):

(1) 这个:

“我告诉约翰把袋子给蒂姆。”

改成这样:

“我告诉蒂姆把袋子给约翰。”

(2) 这个:

“约翰向蒂姆问好。”

改成这样:

“蒂姆向约翰问好。”

(3) 这个:

“约翰!h9aghagTim”

改成这样:

“蒂姆!h9aghagJohn”

【问题讨论】:

  • 有什么方法可以识别字符串吗?你怎么知道这些字符串是你想要的?如果只是位置问题,那么 split() (或者最坏的情况是 csv 模块)就可以了。

标签: python regex string


【解决方案1】:
>>> import re
>>> text = '{text1} {stringA} {text2} {stringB} {text3}'
>>> re.sub(r'(stringA)(.*)(stringB)', r'\3\2\1', text)
'{text1} {stringB} {text2} {stringA} {text3}'

stringAstringB 替换为您感兴趣的子字符串,注意您可能需要re.escape() 以防子字符串在正则表达式中包含具有特殊含义的字符。

测试用例:

>>> stringA = 'John'
>>> stringB = 'Tim'
>>> regex = re.compile(r'(%s)(.*)(%s)' % (stringA, stringB))
>>> regex.sub(r'\3\2\1', "I told John to give the bag to Tim.")
'I told Tim to give the bag to John.'
>>> regex.sub(r'\3\2\1', "John said hello to Tim.")
'Tim said hello to John.'
>>> regex.sub(r'\3\2\1', "John!h9aghagTim")
'Tim!h9aghagJohn'

【讨论】:

  • 谢谢。我不明白% 表示法。它叫什么,以便我可以阅读它?
  • @synaptik - % 用于 string formatting。通常我会建议改用str.format() 方法,但由于它使用方括号,它可能会与您的示例数据混淆。
【解决方案2】:

要采用的方法是使用捕获组,以便您以后可以参考它们

result = re.sub(r"(\{text1\}) (\{stringA\}) (\{text2\}) (\{stringB\}) (\{text3\})", r"\1 \4 \3 \2 \5", subject)

捕获组由括号 () 标识,您在 python 中通过 \x 引用它们,其中 x 是捕获组的编号

更新 1

您的示例使您更清楚您想要什么以及您目前对正则表达式的看法。正则表达式匹配字符模式。你想交换名字(Tom,Tim,...)所以我们需要想出一个模式来匹配一个只有通过完整枚举才有可能的名字。在我的语言中,(我认为)有数千个名字,其中一些也用于指代对象而不是人。要做出这种区分,您必须考虑正则表达式不能考虑的上下文。让我知道这是否有意义,因为如果您想更进一步,这很重要。

更新 2

我怀疑您的问题是出于好奇,而不是为了解决现实生活中的问题。但是,如果我们继续下去,这会让你走得更远,但它并不完美,也不可能

正则表达式

(.*)\b(John|Tim|Jo)\b(.*)\b(John|Tim|Jo)\b

替换为

\1\4\3\2

在python中

result = re.sub(r"(?sm)(.*)\b(John|Tim|Jo)\b(.*)\b(John|Tim|Jo)\b", r"\1\4\3\2", subject)

注意正则表达式中的 \b ,它表明匹配应该发生在单词边界处。这可以防止像 Johndoe 这样的匹配。

还要注意上面的正则表达式对于句子会失败

Tim 从 John 那里购买了一些以 Jo 结尾的 Jordan 顶级域名

【讨论】:

  • 但是如果我不知道 {text1}、{text2} 或 {text3} 是什么?
  • 你应该提供更多关于不同文本的信息。换句话说,我们如何识别每个部分?可能有分隔符吗?你能在你的问题中举一些具体的例子吗?
  • 好点。抱歉,不是很清楚。我只是添加了一些示例。这应该更清楚。 (谢谢)
  • 非常感谢,您的解决方案很有帮助。这个问题是一个玩具问题,但它与我需要做的真实事情非常相似。
猜你喜欢
  • 2016-09-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-10-12
  • 2016-12-24
  • 2015-11-24
  • 2021-06-13
  • 1970-01-01
相关资源
最近更新 更多