【问题标题】:line.replace is replacing with value even for a portion of key match instead of entire key matchline.replace 即使对于部分键匹配而不是整个键匹配也用值替换
【发布时间】:2015-01-23 23:48:25
【问题描述】:
#!/usr/bin/python
import socket
import subprocess

ip=socket.gethostbyname(socket.gethostname())

reps= {'application.baseUrl': 'application.baseUrl="http://'+ip+':9000"',
'baseUrl': 'baseUrl="http://'+ip+':9000"'
}

f = open('/opt/presentation/conf/application.conf','r+')
lines = f.readlines()

f.seek(0)
f.truncate()

for line in lines:
        for key in reps.keys():

            if key in line:
                line = line.replace(line, reps[key])
        f.write(line+'\n')
f.close()

问题:它将 application.baseUrl 替换为 baseUrl="http://'+ip+':9000 而不是 application.baseUrl="http://'+ip+':9000,因为 baseUrl 在 application.baseUrl 中。

只有当它匹配整个字符串而不是字符串的一部分时,我如何替换一个键

文件名:abc.config

application.baseUrl="http://ip:9000"

baseUrl="http://ip:9000"

远程{

log-received-messages = on

netty.tcp {

  hostname = "ip"

  port = 9999

  send-buffer-size = 512000b

  receive-buffer-size = 512000b

  maximum-frame-size = 512000b

  server-socket-worker-pool {

    pool-size-factor = 4.0

    pool-size-max = 64

  }

  client-socket-worker-pool {

    pool-size-factor = 4.0

    pool-size-max = 64

  }

}

}

【问题讨论】:

  • 请注意,您根本不需要进行任何测试(即'foo'.replace('Q','Z') 只返回'foo',因此您不必在调用@ 之前确保密钥在行中987654327@),但是由于您的一个键是另一个键的子集,因此没有正则表达式就没有很好的方法。
  • application.conf 看起来像什么?您能否提供一些预期的输入/输出?
  • 这里是配置文件格式:文件名:abc.config application.baseUrl="ip:9000" baseUrl="ip:9000" remote { log-received-messages = on netty.tcp { hostname =“ip”端口 = 9999 发送缓冲区大小 = 512000b 接收缓冲区大小 = 512000b 最大帧大小 = 512000b 服务器套接字工作池 { 池大小因子 = 4.0 池大小最大值 = 64 } client-socket-worker-pool { pool-size-factor = 4.0 pool-size-max = 64 } } }

标签: python regex python-2.7 python-3.x


【解决方案1】:

由于您想要精确匹配而不是检查:

if key in line:

你应该这样做:

if key == line[0:len(key)]:

或者更好,正如 Adam 在下面的 cmets 中建议的那样:

if line.startswith(key):

【讨论】:

  • 除非它没有开始行,如果是,你应该使用if line.startswith(key)。这样做的唯一可靠方法是if any(key == line[start:start+len(key)] for start in range(0,len(line)-len(key)))
  • 感谢 Alfasin 和 Adam。
  • if key == line[0:len(key)]:​​ 它确实适用于上述问题。但如果文件有:netty.tcp { hostname = "ip" port = 9999 pool-size=4.0} 则不是。它找不到“主机名”或“端口”来替换密钥
  • @bvr 如果文件是 json 格式 - 最好使用 json 解析器(python 中有一个 json 模块)。
  • @AdamSmith 试图处理各种奇怪的边缘情况在这种情况下似乎有点矫枉过正。它会使代码变得混乱,而且几乎没有用处,影响性能并且难以维护。
【解决方案2】:

您可以改用正则表达式:

re.sub(r"\b((?:application\.)?baseUrl)\b", r"\1=http://{}:9000".format(ip))

这将匹配application.baseUrl,替换为application.baseUrl=http://IP_ADDRESS_HERE:9000,和baseUrl,替换为baseUrl=http://IP_ADDRESS_HERE:9000

正则表达式解释:

re.compile(r"""
  \b                             # a word boundary
  (                              # begin capturing group 1
    (?:                            # begin non-capturing group
      application\.                  # application and a literal dot
    )?                             # end non-capturing group and allow 1 or 0 occurrences
    baseUrl                        # literal baseUrl
  )                              # end capturing group 1
  \b                             # a word boundary""", re.X)

和替换

re.compile(r"""
  \1                             # the contents of capturing group 1
  =http://                       # literal
  {}                             # these are just brackets for the string formatter
  :9000                          # literal""".format(ip), re.X)
# resulting in `r"\1=http://" + ip + ":9000"` precisely.

【讨论】:

  • 我不建议使用正则表达式,除非它使代码更具可读性或使任务更简单。这种情况都不是。
  • @alfasin 我会说它使任务变得非常简单,考虑到您必须为\b自动捕获的边缘情况编写多少代码
  • 考虑到我没有处理 any 这样的边缘情况,也不打算为此编写代码,这并不简单。此外,与子字符串相比,使用正则表达式(在任何语言中)的速度都非常慢。
  • @alfasin 我同意你的观点,除了你的解决方案适用于 op 的测试用例而不是他们的实际问题,根据 op 对你的答案的评论。我的解决方案比您想象的 op 需要的更强大,但是您的解决方案对于他们的用例来说太脆弱了。我会选择任何一天都可以使用的稍微慢一点的解决方案......
  • 如果测试用例不能反映实际问题,则应更改问题:)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-01-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多