Я пытаюсь извлечь некоторую информацию из файла tnsnames с помощью regex. Я начал со следующего шаблона:
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)
)
)
Хорошо, так как я не нашел убедительного ответа на этот вопрос (без обид @Mikael Svenson), я просто застрял со вторым шаблоном, указанным в моем вопросе. Достаточно пока, так как файл tnsnames.ora всегда следует этому точному шаблону в нашей организации. Если формат файла tnsnames.ora изменится, я скорее всего возьму синтаксический анализатор.
Это должно быть сделано, используя сбалансированные группы. И измените переключатель/футляр для ваших нужд.
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)
)
)
";
}
Это выражение проанализирует схему с одним адресом в address_list и т.д. Надеюсь, это поможет.
- начать (? > ((? [\ П] [\ s] [^ (] [\ ш _.] +) [\ S] = [\ s])) (? > (? [\n\S (] ОПИСАНИЕ [\s =\s] (? > (?\s [\ п (] * ADDRESS_LIST [\ s =\s] * [\ п \s (] ADDRESS [\ s =\s] (? ([\ п\с (] СООБЩЕСТВО) ([\n\s (] СООБЩЕСТВО [\ s =\s] ([\ ш)] +)?.) |?()) [\ s\п] (([\n\s (] ПРОТОКОЛ) ([\n\s (] ПРОТОКОЛ [\ s =\s] ([\ ш)] +)?.) |?()) [\ s\п] (([\n\s ( ] ХОСТ) ([\n\s (] ХОСТ [\ s =\s] ([\ ш)] +?.)) |?()) [\ s\п] (([\n\s (] ПОРТ) ([\n\s (] ПОРТ [\ s =\s] ([\ ш).] +?)) |()) [\ s\п] (())()) |?() ))) [\ s\п] (? > (? [\ п] [\ s] [(] CONNECT_DATA\s * [=]\s * [\ п] (? ([(] SID\с [= ]\s *) (([(] SID\S * [=]\s * ([\ ш] +)\с * [)]?.)) |()?) [\ s\п] (( [(] SERVER\s [=]\S *) (([(] Сервер \S * [=]\s * ([\ ш.] +)\с * [)])?) |()) [\s\п] * (? ([(] sERVICE_NAME\s * [=]\s *) (([(] service_name\s * [=]\s * (? [\ ш.] +)\s * [)])) |()) [\ s\п] (())()) |()?))) [\ s\п] (())()) |()?))) * - конец
Несомненно, проблема заключается в множественности, которая находится в форме записи этого файла. Как вы говорите, файл должен быть уникальным, это решается с помощью переменной TNS_ADMIN.