Python/RE 将 tnsnames.ora 解析为连接字符串

Python/RE Parse tnsnames.ora into connection strings

我正在开发一个函数来从 tnsnames.ora 检索特定的连接字符串并设置它们以供 cx_Oracle 稍后使用。我决定学习“正则表达式”是正确的方法,但它给我带来的麻烦比我想象的要多。感谢任何帮助将每个条目折叠成一行且没有空格并匹配条目的帮助。
来自 tnsnames.ora 个文件的片段:

ExPRD =
  (DESCRIPTION =
    (ADDRESS = (PROTOCOL = TCP)(HOST = whatever.com)(PORT = 0000))
    (ADDRESS = (PROTOCOL = TCP)(HOST = whatever2.com)(PORT = 0000))
    (CONNECT_DATA =
      (SERVER = DEDICATED)
      (SERVICE_NAME = ExPRD)
    )
  )

ExQAT =
 (DESCRIPTION =
    (ADDRESS = (PROTOCOL = TCP)(HOST = whatever.com)(PORT = 0000))
    (ADDRESS = (PROTOCOL = TCP)(HOST = whatever2.com)(PORT = 0000))
    (CONNECT_DATA =
      (SERVER = DEDICATED)
      (SERVICE_NAME = ExQAT)
    )
  )

ExTST =
  (DESCRIPTION =
    (ADDRESS = (PROTOCOL = TCP)(HOST = whatever.com)(PORT = 0000))
    (ADDRESS = (PROTOCOL = TCP)(HOST = whatever2.com)(PORT = 0000))
    (CONNECT_DATA =
      (SERVER = DEDICATED)
      (SERVICE_NAME = ExTST)
    )
  )

想要的结果,设置以下全局变量:

exprd_cs = (DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(HOST= whatever.com)(PORT=0000))(ADDRESS=(PROTOCOL=TCP)(HOST= whatever2.com)(PORT=0000))(CONNECT_DATA=(SERVER=DEDICATED)(SERVICE_NAME=ExPRD)))
extst_cs = (DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(HOST= whatever.com)(PORT=0000))(ADDRESS=(PROTOCOL=TCP)(HOST= whatever2.com)(PORT=0000))(CONNECT_DATA=(SERVER=DEDICATED)(SERVICE_NAME=ExTST)))

Python 脚本:

import re

tns_file = path/tnsnames.ora

def Read_File(FILENAME, LINE): 
    try:
        if LINE == 'NO':
            with open(FILENAME) as opened_file:
                file_string = opened_file.read()
        if LINE == 'YES':
            with open(FILENAME) as opened_file:
                file_string = opened_file.readline()
    except IOError as e:
         print("File Failed to Open;", e)
         raise e
    except Exception as e:
         print("Read File Failed;", e)
         raise e
    return file_string

def Get_TNS_Config():
    global exprd_cs
    global extst_cs
    tns_config = Read_File(tns_file, 'YES')

(找到一种将配置条目折叠成单行且无空格的方法)

(continued...)
    for match in re.finditer(r'<db>=<db_cs>', tns_config):
        if match.group(1) == ‘ExPRD’:
            exprd_cs = match.group(2)
        if match.group(1) == ‘ExTST’:
            extst_cs = match.group(2)

Get_TNS_Config()

获取变量的一种方法可能是首先使用 sub 创建没有空格的行和一个正则表达式,该正则表达式匹配一次或多次空白字符,并带有否定前瞻性断言后面的内容不是ExPRDExQATExTST 在行首并替换为空字符串:

\s+(?!^Ex(?:PRD|QAT|TST))

Regex demo

然后使用 finditer 使用 2 个捕获组 ^(Ex(?:PRD|QAT|TST))(.*),您可以在其中检查第一个捕获组并相应地分配第二个捕获组。

Regex demo

Python demo

例如

tns_config = """ExPRD =
  (DESCRIPTION =
    (ADDRESS = (PROTOCOL = TCP)(HOST = whatever.com)(PORT = 0000))
    (ADDRESS = (PROTOCOL = TCP)(HOST = whatever2.com)(PORT = 0000))
    (CONNECT_DATA =
      (SERVER = DEDICATED)
      (SERVICE_NAME = ExPRD)
    )
  )

ExQAT =
 (DESCRIPTION =
    (ADDRESS = (PROTOCOL = TCP)(HOST = whatever.com)(PORT = 0000))
    (ADDRESS = (PROTOCOL = TCP)(HOST = whatever2.com)(PORT = 0000))
    (CONNECT_DATA =
      (SERVER = DEDICATED)
      (SERVICE_NAME = ExQAT)
    )
  )

ExTST =
  (DESCRIPTION =
    (ADDRESS = (PROTOCOL = TCP)(HOST = whatever.com)(PORT = 0000))
    (ADDRESS = (PROTOCOL = TCP)(HOST = whatever2.com)(PORT = 0000))
    (CONNECT_DATA =
      (SERVER = DEDICATED)
      (SERVICE_NAME = ExTST)
    )
  )"""


regex = r"\s+(?!^Ex(?:PRD|QAT|TST))"
result = re.sub(regex, '', tns_config, 0, re.MULTILINE)
exprd_cs = ""
extst_cs = ""

if result:
    for match in re.finditer(r'^(Ex(?:PRD|QAT|TST))(.*)', result, re.MULTILINE):
        if match.group(1) == 'ExPRD':
            exprd_cs = match.group(2)
        if match.group(1) == 'ExTST':
            extst_cs = match.group(2)

print(exprd_cs)
print(extst_cs)