簡體   English   中英

使用正則表達式解析tnsnames.ora

[英]Parsing tnsnames.ora using regex

我試圖使用正則表達式從我的tnsnames文件中提取一些信息。 我從以下模式開始:

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條目中出現的每個元素,如果它不包含所有相同的元素,它將不匹配MYOTHERSCHEMA。

理想情況下,我想要一個僅匹配MYSCHEMA條目的模式,並捕獲HOST,PORT和SERVICE NAME,並可選地(SERVER = DEDICATED)(我在第一個模式中沒有)到命名組。

下面是我用於測試的示例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)
    )
  )

這應該使用平衡組來完成。 並根據您的需要修改開關/外殼。

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

以下正則表達式將解析單個TNS條目,您所要做的就是解析每個結果您認為適合名稱/值的方式

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

示例: https//regexr.com/3r2vn

好吧,既然我沒有找到這個問題的令人信服的答案(沒有進攻@Mikael Svenson),我只是堅持我的問​​題中列出的第二種模式。 暫時就足夠了,因為tnsnames.ora文件始終遵循組織內的確切模式。 如果tnsnames.ora文件格式發生變化,我很可能會采用解析器。

此表達式使用address_list上的一個地址解析模式。希望這會有所幫助。

--begin(?>((?[\\ n] [\\ s] [^(] [\\ w _。] +)[\\ s] = [\\ s] ))(?>(?[\\ n \\ s( ] DESCRIPTION [\\ s = \\ s] (?>(?[\\ n \\ s(] * ADDRESS_LIST [\\ s = \\ s] * [\\ n \\ s(] ADDRESS [\\ s = \\ s] (?([ \\ n \\ s(]社區)([\\ n \\ s(]社區[\\ s = \\ s] (?[\\ w。]] +))|())[\\ s \\ n] (?([\\ n \\ s(] PROTOCOL)([\\ n \\ s(] PROTOCOL [\\ s = \\ s] (?[\\ w。)] +))|())[\\ s \\ n] (?([\\ n] \\ s(] HOST)([\\ n \\ s(] HOST [\\ s = \\ s] (?[\\ w。]] +))|())[\\ s \\ n] (?([\\ n \\ n] s(] PORT)([\\ n \\ s(] PORT [\\ s = \\ s] (?[\\ w。)] +))|())[\\ s \\ n] (?())()) |())))[\\ s \\ n] (?>(?[\\ n] [\\ s] [(] CONNECT_DATA \\ s * [=] \\ s * [\\ n] (?([(] SID \\ s [=] \\ 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 *(?[\\瓦特] +) \\ 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 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM