2010-08-23 5 views
2

J'essaie de tirer quelques informations de mon fichier tnsnames en utilisant regex. J'ai commencé avec le schéma suivant:Analyser tnsnames.ora en utilisant regex

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 ne contient pas tous les mêmes éléments. Idéalement, je voudrais un modèle qui correspond uniquement à l'entrée MYSCHEMA, et qui capture HOST, PORT et SERVICE NAME, et éventuellement (SERVER = DEDICATED) (que je n'avais pas dans le premier modèle) à des groupes nommés.

est Ci-dessous l'échantillon tnsnames que j'ai utilisé pour les tests:

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

duplication possible de [Tnsnames.ora parsing dans Visual C# 2008] (http: // stackoverflow.com/questions/1243022/parsing-tnsnames-ora-in-visual-c-2008) – Kobi

+1

Regex ne fonctionne pas bien avec des parenthèses équilibrées, voir le lien dans le commentaire précédent pour une meilleure solution. – Kobi

+0

@Kobi - Je ne peux pas justifier l'ajout d'un autre produit tiers à notre environnement de développement pour quelque chose qui peut être accompli par d'autres moyens. –

Répondre

0

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. C'est suffisant pour l'instant, car le fichier tnsnames.ora suit toujours ce modèle précis au sein de notre organisation. Si le format du fichier tnsnames.ora change, j'utiliserai probablement un analyseur.

2

Cela devrait le faire, en utilisant des groupes équilibrés. Et modifiez 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) 
     ) 
    ) 
    "; 
} 
+0

J'ai essayé votre solution ci-dessus, en remplaçant les longues chaînes d'espaces littérales par \ s *, mais elle ne trouve plus de correspondance lorsque j'inclus le groupe Settings-Open. –

+0

Conserve les espaces littéraux .. ils sont pris en charge avec l'option RegexOptions.IgnorePatternWhitespace. Si vous voulez les supprimer, il suffit de supprimer les espaces, ne le remplacez pas. –

+0

Oups, désolé. Je venais de copier le modèle d'expression régulière dans RegexBuddy pour faire un test rapide sur mon échantillon, et j'ai rencontré le problème mentionné ci-dessus. Je n'avais pas remarqué les RegexOptions. –

0

Cette expression analyse le schéma avec une adresse sur liste_adresses, etc. Espérons que cela vous aide.

--begin (?> ((? [\ N] [\ s] [^ (] [\ w _.] +) [\ S] = [\ s])) (? > (? [\ n \ s() DESCRIPTION [\ s = \ s] (?> (? [\ n \ s (] * ADDRESS_LIST [\ s = \ s] * [\ n \ s (] ADRESSE [\ s = \ s] (? ([\ N \ s (] COMMUNITY) ([\ n \ s (] COMMUNITY [\ s = \ s] (? [\ W.)] +)) |()) [\ s \ n] (? ([\ n \ s (] PROTOCOLE) ([\ n \ s (] PROTOCOLE [\ s = \ s] (? [\ w.)] +)) |()) [\ s \ n] (? ([\ n \ s (] HÔTE) ([\ n \ s (] HÔTE [\ 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] (? ([(] SID \ [=] \ s *) (([(] SID \ s * [=] \ s * (? [\ w.] +) \ s * [) ])) |()) [\ s \ n] (? ([(] SERVER \ s [=] \ s *) (([(] SERVER \ s * [=] \ s * (? w.] +) \ s * [)])) |()) [\ s \ n] * (? ([(] SERVICE_NAME \ s * [=] \ s *) (([(] SERVICE_NAME \ s * [=] \ s * (? [\ w.] +) \ s * [)])) |()) [\ s \ n] (?())()) |()))) [\ s \ n] (?())()) |()))) * - fin

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

Questions connexes