سؤال

أحاول سحب بعض المعلومات من ملف 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 ، ولن يتطابق مع motherchema إذا لم يحتوي على جميع العناصر نفسها.

من الناحية المثالية ، أود أن يكون نمطًا يتطابق مع إدخال MySchema فقط ، ويلتقط اسم المضيف والمنفذ والخدمة ، واختياريًا (خادم = مخصص) (الذي لم يكن لدي في النمط الأول) للمجموعات المسماة.

فيما يلي عينة 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)
    )
  )
هل كانت مفيدة؟

المحلول 3

حسنًا ، نظرًا لأنني لم أجد إجابة مقنعة على هذه المشكلة (لا توجد جريمة Mikael Svenson) ، فقد علقت للتو بالنمط الثاني المدرج في سؤالي. إنه يكفي في الوقت الحالي ، حيث يتبع ملف tnsnames.ora دائمًا هذا النمط الدقيق داخل مؤسستنا. إذا كان تغيير تنسيق ملف tnsnames.ora ، فسأعتمد على الأرجح محللًا.

نصائح أخرى

هذا يجب أن يفعل ذلك ، باستخدام مجموعات متوازنة. وتعديل التبديل/الحالة لاحتياجاتك.

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

سيقوم Regex التالي بتحليل إدخالات TNS الفردية ، وكل ما عليك فعله هو تحليل كل نتيجة كيف تراه مناسبًا للأسماء / القيم

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

مثال: https://regexr.com/3r2vn

هذا التعبير تحليل المخطط بعنوان واحد على العنوان ، وما إلى ذلك. آمل أن يساعد هذا.

-begin (؟> ((؟ [ n] [ s^(] [ w _.]+) [ s= [ s)) (؟> (؟ [ n s (الوصف [ s = s(؟> (؟ [ n s (]*address_list [ s = s]*[ n s (العنوان [ s = s(؟ ([ n s (] مجتمع) ([ n s (] المجتمع [ s = s(؟ [ w.)]+)) | ()) [ s n(؟ ([ n s (] بروتوكول) ([ n s (] بروتوكول [ s = s(؟ [ w.)]+)) | ()) [ s n(؟ ([ n s (] مضيف) ([ n s (] مضيف [ s = s(؟ [ w.)]+)) | ()) [ s n(؟ ([ n s (] منفذ) ([ n s (] منفذ [ s = s(؟ [ w.)]+)) | ()) [ s n(؟ ()) () | ()))) [ s n(؟> (؟ [ n] [ s(] connect_data s*[=] s*[ n(؟ ([(] sid s=] s*) (([(] sid s*[=] s*(؟ [ w.]+) s*[))) | ()) [ s n(؟ ([(] خادم s=] s*) (([(] server s*[=] s*(؟ [ w.]+) s*[))) | ()) [ s n]** (؟ ([(] service_name s*[=] s*) (([(] service_name s*[=] s*(؟ [ w.]+) s*[)]) | ()) [ s n(؟ ()) () | ()))) [ s n(؟ ()) ()) | ()))) *-نهاية

مما لا شك فيه ، المشكلة هي المتعددة الموجودة في شكل كتابة هذا الملف. كما تقول أن الملف يجب أن يكون فريدًا ، يتم حل هذا باستخدام متغير TNS_ADMIN.

جربت الإجابات أعلاه ولم يعمل أي منها ...

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


 }
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top