Разбор tnsnames.ora с помощью регулярных выражений - PullRequest
2 голосов
/ 23 августа 2010

Я пытаюсь извлечь некоторую информацию из моего файла 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, и, опционально (SERVER = DEDICATED) (которого у меня не было в первом шаблоне) для именованных групп. 1015 *

Ниже приведен пример 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)
    )
  )

Ответы [ 4 ]

2 голосов
/ 23 августа 2010

Это следует делать, используя сбалансированные группы. И измените переключатель / чехол для ваших нужд.

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)
        )
      )
    ";
}
0 голосов
/ 17 июня 2018

Следующее регулярное выражение будет анализировать отдельные записи TNS, и все, что вам нужно сделать, - это проанализировать каждый результат, как вы считаете подходящим для имен / значений

([\w-]+)\s*=(?:\s|.)+?\)\s*\)\s*\)\s*(?=[\w\-])

Пример: https://regexr.com/3r2vn

0 голосов
/ 27 декабря 2010

Это выражение анализирует схему с одним адресом в address_list и т. Д. Надеюсь, это поможет.

- начало (?> ((? [\ П] [\ s] [^ (] [\ ш _.] +) [\ S] = [\ s] )) (?> (? [\ N \ s (] ОПИСАНИЕ [\ s = \ с] (?> (? [\ s \ п (] * ADDRESS_LIST [\ s = \ s] * [\ N \ s (] АДРЕС [\ s = \ с] (? ([\ N \ s (] СООБЩЕСТВО) ([\ N \ s (] СООБЩЕСТВО [\ s = \ с] (? [\ ш .)] +)) | ()?) [\ s \ п] (([\ N \ s (] ПРОТОКОЛ) ([\ N \ s (] ПРОТОКОЛ [\ s = \ s] (? [\ ш.)] +)) | ()) [\ s \ п] (([\ N \ s (] HOST) ([\ п \ s (] HOST [\ s = \? s] ] +)) ([\ ш?.) | ()?) [\ s \ п] (([\ N \ s (] PORT) ([\ N \ s (] PORT [\ s = \ s] +)) ([\ ш.?)] | ()) [\ s \ п] (()) ()) | ()?))) [\ с \ п] (?> (? [\ п] [\ s] [(] CONNECT_DATA \ s * [=] \ s * [\ п] * 1 021 * (? ([(] SID \ с [=] \ s *) (([(] SID \ S * [=] \ s * ([\ ш.] +) \ с * [)]?)) | ()) [\ с \ п] * 1 023 * (? ([(] Сервер \ s [=] \ s *) (([(] Сервер \ s * [=] \ s * (? [\ ш.] +) \ S * [)])) | ()?) [\ s \ п] * (([(] SERVICE_NAME \ s * [=] \ s *) (([(] SERVICE_NAME \ s * [=] \ s * \ S * [)])) ([\ ш.] +?) | ()) [\ s \ п] (()) ()) | ()?))) [\ s \ п ] ()) (()?) | ()))) * - конец

Несомненно, проблема в том, что кратно в форме записи этого файла. Поскольку вы говорите, что файл должен быть уникальным, это решается с помощью переменной TNS_ADMIN.

0 голосов
/ 29 сентября 2010

Ну, так как я не нашел убедительного ответа на этот вопрос (без обид @Mikael Svenson), я просто остановился на втором шаблоне, указанном в моем вопросе. Пока этого достаточно, так как файл tnsnames.ora всегда следует именно этому шаблону в нашей организации. Если формат файла tnsnames.ora изменится, я, скорее всего, приму парсер.

...