Pregunta

Estoy intentando sacar algo de información de mi archivo tnsnames usando expresiones regulares. Empecé con la siguiente distribución:

MYSCHEMA *? = *?[\W\w\S\s]*\(HOST *?= *?(?<host>\w+\s?)\)\s?\(PORT *?= *?(?<port>\d+)\s?\)[\W\w\S\s]*\(SERVICE_NAME *?= *?(?<servicename>\w+)\s?\)

que funcionaba bien cuando MYSCHEMA fue el único esquema en el archivo, pero cuando hay otros esquemas que figuran después de MYSCHEMA que coincide todo el camino hasta el último esquema.

He creado desde entonces un nuevo patrón:

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*\)

Este patrón coincide con MYSCHEMA solamente, pero tenía que añadir todos los elementos que apareció en la entrada MYSCHEMA, y no va a coincidir con MYOTHERSCHEMA si no contiene todos los mismos elementos.

Idealmente, me gustaría un patrón que única entrada partidos MYSCHEMA, y capturas de host, el puerto y Nombre de servicio, y opcionalmente (SERVER = DEDICATED) (que no tenía en el primer patrón) a grupos nombrados.

A continuación se muestra los tnsnames que he estado utilizando para la prueba:

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)
    )
  )
¿Fue útil?

Solución 3

Bueno, ya que no he encontrado una respuesta convincente a este problema (sin ofender @Mikael Svenson), acabo de pegado con el segundo patrón que aparece en mi pregunta. Es suficiente por el momento, ya que el archivo tnsnames.ora siempre sigue ese patrón exacto dentro de nuestra organización. En caso de que el cambio de formato de archivo tnsnames.ora, lo más probable es que adopte un programa de análisis.

Otros consejos

Esto debería hacerlo, utilizando grupos equilibrados. Y modificar el interruptor / caja para sus necesidades.

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)
        )
      )
    ";
}

La siguiente expresión regular se omita entradas TNS individuales, y todo lo que tiene que hacer es analizar cada resultado de la forma en que se ve ajuste para los nombres / valores

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

Ejemplo: https://regexr.com/3r2vn

Esta expresión analizar el esquema con una dirección en ADDRESS_LIST, etc. Espero que esto ayude.

- comienzan (?> ((? [\ N] [\ s] [^ (] [\ w _.] +) [\ S] = [\ s] )) (?> (? [\ n \ s (] DESCRIPCIÓN [\ s = \ s] (?> (? [\ n \ s (] * ADDRESS_LIST [\ s = \ s] * [\ n \ s (] DIRECCIÓN [\ s = \ s] (? ([\ n \ s (] COMUNIDAD) ([\ n \ s (] COMUNIDAD [\ s = \ s] ( ? [\ w).] +)) |? ()) [\ s \ n] (([\ n \ s (] PROTOCOLO) ([\ n \ s (] PROTOCOLO [\ s = \ s] ] +)) ([\ w?.) |? ()) [\ s \ n] (([\ n \ s (] HOST) ([\ n \ s (] HOST [\ s = \ s] +)) ([\ w.?)] |? ()) [\ s \ n] (([\ n \ s (] PORT) ([ \ n \ s (] PUERTO [\ s = \ s] ([\ w)] +?.)) |? ()) [\ s \ n] (()) ()) |?? ()))) [\ s \ n] (> ([\ n] [\ s] [(] CONNECT_DATA \ s * [=] \ s * [\ n] < em> (? ([(] SID \ s [=] \ s *) (([(] SID \ s * [=] \ s * (? [\ w.] +) \ s * [ )])) |? ()) [\ s \ n] (([(] SERVIDOR \ s [=] \ s *) (([(] SERVIDOR \ s * [=] \ s * \ s * [)])) ([\ w.] +?) |? ()) [\ s \ n] * (([(] SERVICE_NAMESTART_BREAK \ s * [=] \ s *) (([ (] SERVICE_NAMESTART_BREAK \ s * [=] \ s * ([\ w] +) \ s * [?.)])) |? ()) [\ s \ n] (()) ()) | ()))) [\ s \ n] (()) ()) |? ()))) * - final

Sin lugar a dudas, el problema es el múltiplo que está en la forma de escribir ese archivo. Como usted dice que el archivo debe ser único, esto se resuelve mediante el uso de la variable TNS_ADMIN.

probé las respuestas anteriores y ninguno de ellos trabajó para mí ...

    [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);


 }
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top