3

正規表現を使用して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)
    )
  )
4

5 に答える 5

2

これは、バランスの取れたグループを使用して、それを行う必要があります。そして、必要に応じてスイッチ/ケースを変更します。

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)
        )
      )
    ";
}
于 2010-08-23T18:38:04.253 に答える
1

次の正規表現は、個々のTNSエントリを解析します。必要なのは、名前/値に適していると思われる各結果を解析することだけです。

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

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

于 2018-06-17T02:53:21.497 に答える
0

この式は、address_listなどの1つのアドレスでスキーマを解析します。これがお役に立てば幸いです。

--開始(?>((?[\ n] [\ s] [^(] [\ w_。]+)[\ s] = [\ s]))(?>(?[\ n \ s( ]説明[\s= \ s](?>(?[\ n \ s(] * ADDRESS_LIST [\ s = \ s] * [\ n \ s(] ADDRESS [\ s = \ s](?([ \ n \ s(] COMMUNITY)([\ n \ s(] COMMUNITY [\ 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 \ 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 *(?[\w。]+)\ s * [)]))| ())[\ s \ n] (?())())|())))[\ s \ n](?())())|())))*-end

間違いなく、問題はそのファイルを書き込むという形の倍数です。ファイルは一意である必要があると言うように、これはTNS_ADMIN変数を使用して解決されます。

于 2010-12-27T15:48:59.903 に答える
0

まあ、私はこの問題に対する説得力のある答えを見つけられなかったので(@Mikael Svensonの攻撃はありません)、質問にリストされている2番目のパターンに固執しました。tnsnames.oraファイルは常に組織内でその正確なパターンに従うため、当面はこれで十分です。tnsnames.oraファイル形式が変更された場合、おそらくパーサーを採用します。

于 2010-09-29T19:56:44.173 に答える
0

私は上記の答えを試しましたが、どれも私にはうまくいきませんでした...

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


 }
于 2019-08-09T23:40:32.147 に答える