我试图使用正则表达式从我的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)(我在第一个模式中没有)到命名组。 / p>
以下是我用于测试的示例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)
)
)
答案 0 :(得分:2)
这应该使用平衡组来完成。并根据您的需要修改开关/外壳。
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)
)
)
";
}
答案 1 :(得分:0)
好吧,既然我没有找到这个问题的令人信服的答案(没有进攻@Mikael Svenson),我只是坚持我的问题中列出的第二种模式。暂时就足够了,因为tnsnames.ora文件始终遵循组织内的确切模式。如果tnsnames.ora文件格式发生变化,我很可能会采用解析器。
答案 2 :(得分:0)
此表达式使用address_list等上的一个地址解析模式。 希望这会有所帮助。
- 开始 ?(大于(([\ n]的[\ s]的 [^(] [\ W _] +)[\ s]的 = [\ s]的))(? &GT;([\ n \ S(说明\ S = \ S] (大于????([\ n \ S(] * ADDRESS_LIST [\ S = \ S] * [ \ n \ S( ADDRESS [\ S = \ S] (?([\ n \ S(]社群)([\ n \ S(]社群[\ S = \ S] < EM>([\瓦特?)] +))|?())[\ 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 \ S(] PORT )([\ n \ S(] PORT [\ S = \ S] ([\ w)的。] +?))|?())[\ S \ n]的(()) ())|())))[\ S \ n]的(&gt;有([\ n]的[\ s]的 [(] CONNECT_DATA \ S * [=] \ S * [ \ n]的(?([(] SID \ S [=] \ S *) - (([(] SID \ S * [=] \ S *(?[\瓦特] +) \ S * [)]))|?())[\ S \ n]的(([(] SERVER \ S [=] \ S *) - (([(] SERVER \ S * [=] \ S * \ S * [)]))([\瓦特] +?)|?())[\ S \ n]的*(([(] SERVICE_NAME \ S * [=] \ S * )(([(] SERVICE_NAME \ S * [=] \ S *([\瓦特] +)\ S * [)]))|?())[\ S \ n]的(() )())|())))[\ S \ n]的(())())|?()))) * - 端
毫无疑问,问题在于写文件的形式是多重的。正如您所说,文件必须是唯一的,这可以通过使用TNS_ADMIN变量来解决。
答案 3 :(得分:0)
以下正则表达式将解析单个TNS条目,您所要做的就是解析每个结果,看你认为哪些名称/值
([\w-]+)\s*=(?:\s|.)+?\)\s*\)\s*\)\s*(?=[\w\-])
答案 4 :(得分:0)
我尝试了以上答案,但没有一个对我有用...
[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);
}