Domanda

Sto tentando di estrarre alcune informazioni dal mio file tnsnames usando espressioni regolari. Ho iniziato con il seguente schema:

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

, che ha funzionato bene quando myschema è stato l'unico schema nel file, ma quando ci sono altri schemi elencati dopo myschema che corrisponda fino all'ultimo schema.

Da allora ho creato un nuovo modello:

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

Questo pattern partite myschema solo, ma ho dovuto aggiungere ogni elemento che è apparso in ingresso myschema, e non corrisponderà MYOTHERSCHEMA se esso non contiene tutti gli stessi elementi.

Idealmente, vorrei un modello che solo ingresso partite myschema, e cattura host, la porta e il nome del servizio, e opzionalmente (SERVER = dedicato) (che non ho avuto nel primo modello) per i gruppi denominati.

Di seguito è riportato il tnsnames di esempio che ho usato per il test:

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)
    )
  )
È stato utile?

Soluzione 3

Bene, visto che non ho trovato una risposta convincente a questo problema (senza offesa @Mikael Svenson), ho appena bloccato con il secondo motivo indicato nella mia interrogazione. E 'sufficiente, per il momento, in quanto il file tnsnames.ora segue sempre quel modello esatto all'interno della nostra organizzazione. Se il cambio formato file tnsnames.ora, che sarà molto probabilmente adottare un parser.

Altri suggerimenti

Questo dovrebbe farlo, utilizzando gruppi bilanciati. E modificare l'opzione / caso per le vostre esigenze.

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 seguente espressione regolare sarà analizzare le singole voci di TNS, e tutto quello che dovete fare è analizzare ogni risultato come si vede in forma per i nomi / valori

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

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

Questa espressione analizza lo schema con un indirizzo sul ADDRESS_LIST, etc. Spero che questo aiuti.

- Iniziamo (?> ((? [\ N] [\ s] [^ (] [\ w _.] +) [\ S] = [\ s] )) (?> (? [\ n \ s (] DESCRIZIONE [\ s = \ s] (?> (? [\ n \ s (] * ADDRESS_LIST [\ s = \ s] * [\ n \ s (] INDIRIZZO [\ s = \ s] (? ([\ n \ s] COMUNITARIA () ([\ n \ s (] COMUNITÀ [\ s = \ s] ( ? [\ w).] +)) |? ()) [\ s \ n] (([\ n \ s (] PROTOCOLLO) ([\ n \ s (] PROTOCOLLO [\ 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 *) (([(] SERVER \ s * [=] \ s * \ s * [)])) ([\ w.] +?) |? ()) [\ s \ n] * (([(] SERVICE_NAME \ s * [=] \ s *) (([ (] SERVICE_NAME \ s * [=] \ s * ([\ w] +) \ s * [?.)])) |? ()) [\ s \ n] (()) ()) | ()))) [\ s \ n] (()) ()) |? ()))) * - end

Senza dubbio, il problema è il multiplo che è in forma di scrittura che di file. Come dici tu il file deve essere univoco, questo è risolto usando la variabile TNS_ADMIN.

Ho provato le risposte di cui sopra e nessuno di loro ha lavorato per me ...

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


 }
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top