我正在尝试使用正则表达式从我的 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 条目匹配的模式,并捕获主机、端口和服务名称,以及可选的 (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)
    )
  )
有帮助吗?

解决方案 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)
        )
      )
    ";
}

以下正则将解析单个TNS条目,您要做的就是分析每个结果,您如何看待名称 /值

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

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

此表达式在adversy_list等上用一个地址等地解析了模式。希望这会有所帮助。

-begin(?>((?[ n] [ s])^(] [ w_。]+)[ s= [ s)(?>(?[ n s(])描述[ s = s(?>(?[ n s(]*advelly_list [ s = s]*[ n s(])地址[ s = s(?([ n s(]社区)([ n s(] community [ s = s(?[ w。)]+))|()[ s n(?([ n s(]协议)([ n s(]协议[ s = s(?[ w。)]+))|()[ s n(?([ n s(]主机)([ n s(] host [ 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*)(([(]服务器 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