Question

J'essaie de tirer quelques informations de mon fichier tnsnames utilisant l'expression rationnelle. J'ai commencé avec le schéma suivant:

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

qui a bien fonctionné quand mon_schema était le seul schéma dans le fichier, mais quand il y a d'autres schémas ci-après mon_schema il correspond jusqu'au dernier schéma.

J'ai depuis créé un nouveau modèle:

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

Ce modèle correspond mon_schema seulement, mais je devais ajouter tous les éléments qui apparaît dans l'entrée de mon_schema, et il ne correspond pas à MYOTHERSCHEMA si elle ne contient pas tous les mêmes éléments.

Idéalement, je voudrais un motif qui correspond entrée de mon_schema seulement, et capture hôte, le port et le nom du service et le cas échéant (SERVEUR = DÉDIÉ) (que je n'ai pas eu dans le premier motif) à des groupes nommés.

Ci-dessous l'échantillon tnsnames que j'ai utilisé pour tester:

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)
    )
  )
Était-ce utile?

La solution 3

Eh bien, puisque je ne l'ai pas trouvé de réponse convaincante à cette question (aucune infraction @Mikael Svenson), je viens coincé avec le deuxième motif énuméré dans ma question. Il suffit pour l'instant, que le fichier tnsnames.ora suit toujours ce modèle exact au sein de notre organisation. Si le changement de format de fichier tnsnames.ora, je vais probablement adopter plus d'un analyseur.

Autres conseils

Cela devrait le faire, en utilisant des groupes équilibrés. Et modifier le commutateur / cas pour vos besoins.

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

Le regex suivant parser des entrées individuelles de TNS, et tout ce que vous avez à faire est d'analyser chaque résultat la façon dont vous voyez l'ajustement pour les noms / valeurs

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

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

Cette expression parser le schéma avec une adresse sur ADDRESS_LIST, etc. Espérons que cela aide.

- commencent (?> ((? [\ N] [\ s] [^ (] [\ w _.] +) [\ S] = [\ s] )) (?> * [\ n (? [\ n \ s (] Description [\ s = \ s] (?> (? [\ n \ s (] * ADDRESS_LIST [\ s = \ s] \ s (] ADRESSE [\ s = \ s] (? ([\ n \ s (] COMMUNITY) ([\ n \ s (] COMMUNAUTÉ [\ s = \ s] ( ? [\ w).] +)) | ()) [\ s \ n] (([\ n \ s (] PROTOCOLE) ([\ n \ s (] PROTOCOLE [\ 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] (> ([\ n] [\ s] [(] CONNECT_DATA \ s * [=] \ s * [\ n] < em> (? ([(] SID \ s [=] \ s *) (([(] SID \ s * [=] \ s * (? [\ w.] +) \ s * [ )])) | ()) [\ s \ n] (([(] SERVER \ s [=] \ s *) (([(] SERVEUR s \ * [=] \ s * \ s * [)])) ([\ w.] +?) | ()) [\ s \ n] * (([(] SERVICE_NAME \ s * [=] \ s *) (([ (] SERVICE_NAME \ s * [=] \ s * ([\ w] +) \ s * [?.)])) | ()) [\ s \ n] (()) ()) | ()))) [\ s \ n] (()) ()) | ()))) * - fin

Sans aucun doute, le problème est multiple qui est sous la forme de l'écriture de ce fichier. Comme vous le dites le fichier doit être unique, ce problème résolu en utilisant la variable TNS_ADMIN.

J'ai essayé les réponses ci-dessus et aucun d'entre eux travaillaient pour moi ...

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


 }
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top