[英]Parsing tnsnames.ora using regex
我試圖使用正則表達式從我的tnsnames文件中提取一些信息。 我從以下模式開始:
MYSCHEMA *? = *?[\\W\\w\\S\\s]*\\(HOST *?= *?(?<host>\\w+\\s?)\\)\\s?\\(PORT *?= *?(?<port>\\d+)\\s?\\)[\\W\\w\\S\\s]*\\(SERVICE_NAME *?= *?(?<servicename>\\w+)\\s?\\)
當MYSCHEMA是文件中唯一的模式時,它工作正常,但是當MYSCHEMA之后列出的其他模式一直匹配到最后一個模式時。
我已經創建了一個新模式:
MYSCHEMA *=\\s*\\(DESCRIPTION =\\s*\\(ADDRESS *= *\\(PROTOCOL *= *TCP\\)\\(HOST *= *(?<host>\\w+)\\)\\(PORT *= *(?<port>\\d+)\\)\\)\\s*\\(CONNECT_DATA *=\\s*(?<serverdedicated>\\(SERVER *= *DEDICATED\\))\\s*\\(SERVICE_NAME *= *(?<servicename>[\\w\\.]+) *\\)\\s*\\)\\s*\\)
這個模式只匹配MYSCHEMA,但是我必須添加MYSCHEMA條目中出現的每個元素,如果它不包含所有相同的元素,它將不匹配MYOTHERSCHEMA。
理想情況下,我想要一個僅匹配MYSCHEMA條目的模式,並捕獲HOST,PORT和SERVICE NAME,並可選地(SERVER = DEDICATED)(我在第一個模式中沒有)到命名組。
下面是我用於測試的示例tnsnames:
SOMESCHEMA =
(DESCRIPTION =
(ADDRESS_LIST =
(ADDRESS = (PROTOCOL = TCP)(HOST = REMOTEHOST)(PORT = 1234))
)
(CONNECT_DATA = (SERVICE_NAME = REMOTE)
)
)
MYSCHEMA =
(DESCRIPTION =
(ADDRESS = (PROTOCOL = TCP)(HOST = MYHOST)(PORT = 1234))
(CONNECT_DATA =
(SERVER = DEDICATED)
(SERVICE_NAME = MYSERVICE.LOCAL )
)
)
MYOTHERSCHEMA =
(DESCRIPTION =
(ADDRESS_LIST =
(ADDRESS = (PROTOCOL = TCP)(HOST = MYHOST)(PORT = 1234))
)
(CONNECT_DATA =
(SERVICE_NAME = MYSERVICE.REMOTE)
)
)
SOMEOTHERSCHEMA =
(DESCRIPTION =
(ADDRESS_LIST =
(ADDRESS = (PROTOCOL = TCP)(HOST = LOCALHOST)(PORT = 1234))
)
(CONNECT_DATA =
(SERVICE_NAME = LOCAL)
)
)
這應該使用平衡組來完成。 並根據您的需要修改開關/外殼。
class TnsRegex
{
public void Test()
{
Regex reTns = new Regex(_pattern, RegexOptions.Singleline | RegexOptions.IgnorePatternWhitespace);
MatchCollection matchCollection = reTns.Matches(_text);
foreach (Match match in matchCollection)
{
foreach (Capture capture in match.Groups["Settings"].Captures)
{
string[] setting = capture.Value.Split(new[] { '=' }, StringSplitOptions.RemoveEmptyEntries);
string key = setting[0].Trim();
string val = setting[1].Trim();
if (val.Contains("(")) continue;
switch (key)
{
case "HOST":
break;
case "PORT":
break;
case "SERVICE_NAME":
break;
case "SERVER":
break;
}
Console.WriteLine(key + ":" + val);
}
}
}
string _pattern = @"
MYSCHEMA\s+=\s+\(
[^\(\)]*
(
(
(?<Open>\()
[^\(\)]*
)+
(
(?<Settings-Open>\))
[^\(\)]*
)+
)*
(?(Open)(?!))
\)";
string _text = @"
MYSCHEMA =
(DESCRIPTION =
(ADDRESS = (PROTOCOL = TCP)(HOST = MYHOST)(PORT = 1234))
(CONNECT_DATA =
(SERVER = DEDICATED)
(SERVICE_NAME = MYSERVICE.LOCAL )
)
)
SOMESCHEMA =
(DESCRIPTION =
(ADDRESS_LIST =
(ADDRESS = (PROTOCOL = TCP)(HOST = REMOTEHOST)(PORT = 1234))
)
(CONNECT_DATA = (SERVICE_NAME = REMOTE)
)
)
";
}
以下正則表達式將解析單個TNS條目,您所要做的就是解析每個結果您認為適合名稱/值的方式
([\\w-]+)\\s*=(?:\\s|.)+?\\)\\s*\\)\\s*\\)\\s*(?=[\\w\\-])
示例: https : //regexr.com/3r2vn
好吧,既然我沒有找到這個問題的令人信服的答案(沒有進攻@Mikael Svenson),我只是堅持我的問題中列出的第二種模式。 暫時就足夠了,因為tnsnames.ora文件始終遵循組織內的確切模式。 如果tnsnames.ora文件格式發生變化,我很可能會采用解析器。
此表達式使用address_list上的一個地址解析模式。希望這會有所幫助。
--begin(?>((?[\\ n] [\\ s] [^(] [\\ w _。] +)[\\ s] = [\\ s] ))(?>(?[\\ n \\ s( ] DESCRIPTION [\\ s = \\ s] (?>(?[\\ n \\ s(] * ADDRESS_LIST [\\ s = \\ s] * [\\ n \\ s(] ADDRESS [\\ s = \\ s] (?([ \\ n \\ s(]社區)([\\ n \\ s(]社區[\\ s = \\ s] (?[\\ w。]] +))|())[\\ s \\ n] (?([\\ n \\ s(] PROTOCOL)([\\ n \\ s(] PROTOCOL [\\ s = \\ s] (?[\\ w。)] +))|())[\\ s \\ n] (?([\\ n] \\ s(] HOST)([\\ n \\ s(] HOST [\\ s = \\ s] (?[\\ w。]] +))|())[\\ s \\ n] (?([\\ n \\ n] s(] PORT)([\\ n \\ s(] PORT [\\ s = \\ s] (?[\\ w。)] +))|())[\\ s \\ n] (?())()) |())))[\\ s \\ n] (?>(?[\\ n] [\\ s] [(] CONNECT_DATA \\ s * [=] \\ s * [\\ n] (?([(] SID \\ s [=] \\ s *)(([(] SID \\ s * [=] \\ s *(?[\\ w。] +)\\ s * [)]))|())[\\ s \\ n] (?([(] SERVER \\ s [=] \\ s *)(([(] SERVER \\ s * [=] \\ s *(?[\\ w。] +)\\ s * [)]))|( ))[\\ S \\ n]的*(?([(] SERVICE_NAME \\ S * [=] \\ S *) - (([(] SERVICE_NAME \\ S * [=] \\ S *(?[\\瓦特] +) \\ s * [)])| |())[\\ s \\ n] (?())())|())))[\\ s \\ n] (?())())|()) )) * - 結束
毫無疑問,問題是以編寫該文件的形式存在的多重問題。 正如您所說的文件必須是唯一的,這可以通過使用TNS_ADMIN變量來解決。
我嘗試了上面的答案,但沒有一個能為我工作......
[DebuggerDisplay("Name {Name} Host:{Host} ServiceName:{ServiceName} Port:{Port}")]
public class TnsEntry
{
public string Name { get; set; }
public string Host { get; set; }
public string Port { get; set; }
public string ServiceName { get; set; }
}
public class TnsNamesFileParser
{
public string TNSNamesContents { get; set; }
public TnsNamesFileParser()
{
}
public TnsNamesFileParser(string locationAndNameOfTnsNamesFile)
{
TNSNamesContents = System.IO.File.ReadAllText(locationAndNameOfTnsNamesFile);
}
public List<TnsEntry> Parse()
{
return Parse(TNSNamesContents);
}
public List<TnsEntry> Parse(string TNSNamesContents)
{
string TNSPattern = @"([\w -] +)\s *= (?:\s |.) +?\)\s *\)\s *\)\s * ((?=[\w\-])|(?=$))";
Regex reTns = new Regex(TNSPattern, RegexOptions.Singleline | RegexOptions.IgnorePatternWhitespace);
MatchCollection matchCollection = reTns.Matches(TNSNamesContents);
var TnsEntries = new List<TnsEntry>();
foreach (Match match in matchCollection)
{
var tnsEntry = new TnsEntry();
string matchedValue = match.Value.Trim();
tnsEntry.Name = Regex.Match(matchedValue, @"^([^\s]+)", RegexOptions.IgnoreCase)?.Value.Trim();
tnsEntry.Host = Regex.Match(matchedValue, "(?<=HOST.+=) ([^)]*)", RegexOptions.IgnoreCase)?.Value.Trim();
tnsEntry.Port = Regex.Match(matchedValue, "(?<=PORT.+=) ([^)]*)", RegexOptions.IgnoreCase)?.Value.Trim();
tnsEntry.ServiceName = Regex.Match(matchedValue, "(?<=SERVICE_NAME.+=) ([^)]*)", RegexOptions.IgnoreCase)?.Value;
TnsEntries.Add(tnsEntry);
}
return TnsEntries;
}
}
//Test Code:
string testdata =@"
SOMESCHEMA =
(DESCRIPTION =
(ADDRESS_LIST =
(ADDRESS = (PROTOCOL = TCP)(HOST = REMOTEHOST)(PORT = 1234))
)
(CONNECT_DATA = (SERVICE_NAME = REMOTE)
)
)
MYSCHEMA =
(DESCRIPTION =
(ADDRESS = (PROTOCOL = TCP)(HOST = MYHOST)(PORT = 1234))
(CONNECT_DATA =
(SERVER = DEDICATED)
(SERVICE_NAME = MYSERVICE.LOCAL )
)
)
MYOTHERSCHEMA =
(DESCRIPTION =
(ADDRESS_LIST =
(ADDRESS = (PROTOCOL = TCP)(HOST = MYHOST)(PORT = 1234))
)
(CONNECT_DATA =
(SERVICE_NAME = MYSERVICE.REMOTE)
)
)
SOMEOTHERSCHEMA =
(DESCRIPTION =
(ADDRESS_LIST =
(ADDRESS = (PROTOCOL = TCP)(HOST = LOCALHOST)(PORT = 1234))
)
(CONNECT_DATA =
(SERVICE_NAME = LOCAL)
)
)";
[Test]
public void ParseTNSFileEntries()
{
var tnsNamesFileParser = new TnsNamesFileParser();
var entries = tnsNamesFileParser.Parse(testdata);
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.