Разбор tnsnames.ora с помощью регулярных выражений

2

Я пытаюсь извлечь некоторую информацию из файла 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)
    )
  )
  • 1
    возможный дубликат синтаксического анализа tnsnames.ora в Visual C # 2008
  • 1
    Regex не очень хорошо работает со сбалансированными скобками, см. Ссылку в предыдущем комментарии для лучшего решения.
Показать ещё 2 комментария
Теги:
tnsnames

3 ответа

0
Лучший ответ

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

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)
        )
      )
    ";
}
  • 0
    Я попробовал ваше решение выше, заменив длинные строки буквальных пространств на \ s *, но он не находит совпадений, когда я включаю группу «Настройки-Открыть».
  • 0
    Сохраняйте литеральные пробелы .. о них заботятся с помощью опции RegexOptions.IgnorePatternWhitespace. Если вы хотите удалить их, просто удалите пробел, не заменяйте его.
Показать ещё 1 комментарий
0

Это выражение проанализирует схему с одним адресом в 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.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню