4

ユーザーがフォルダー階層内のアイテムの「ワイルドカード」パスと、アイテムがそのパスに一致したときに実行される関連アクションを指定できるようにする機能に取り組んでいます。例えば:

    Path         Action
    -----------  -------
 1. $/foo/*/baz  include
 2. $/foo/bar/*  exclude

上記の例では、アイテム at$/foo/bar/bazは両方のアクションに一致します。これを踏まえて、最初のワイルドカード文字が出現する「深さ」に基づいて、ワイルドカードパスの特異性の粗いスコアを提供したいと思います。最も深さのあるパスが勝ちます。重要なのは、*スラッシュ ( /*/) で区切られたもののみがワイルドカードとして許可され (最後に then がある場合を除く/*)、パスのさまざまなポイントで任意の番号を指定できることです。

TL;DR;

したがって、最初のスラッシュより前のスラッシュの数をカウントする正規表現が適していると思います*。ただし、いくつかの理由により、パスにワイルドカードがない場合、スラッシュの一致はゼロになります。私は次の否定的な後読みをしています:

 (?<!\*.*)/

これは、ワイルドカードがある場合 (たとえば、上記のパス #1 に 2 つのスラッシュが一致し、#2 に 3 つのスラッシュが一致する場合) は正常に機能しますが、ワイルドカードがない場合は、すべてのスラッシュに自然に一致します。どれにも一致しないのは簡単なステップだと確信していますが、さびた正規表現スキルのために行き詰まっています。

理想的には学術的な観点から、単一の正規表現でこれをキャプチャできるかどうかを確認したいと思いますが、問題に対するよりエレガントな解決策としてボーナスポイントが提供されます!

4

3 に答える 3

2

これはそれを行う1つの方法です:

match = Regex.Match(subject, 
    @"^       # Start of string
    (         # Match and capture in group number 1...
     [^*/]*   #  any number of characters except slashes or asterisks
     /        #  followed by a slash
    )*        # zero or more times.
    [^*/]*    # Match any additional non-slash/non-asterisk characters.
    \*        # Then match an asterisk", 
    RegexOptions.IgnorePatternWhitespace);

文字列にアスタリスクがない場合、この正規表現は一致しませんsubject(スコアは0)。正規表現が一致する場合、少なくとも 1 つのアスタリスクが含まれていることを確認できます。

巧妙なことに、.NET 正規表現は、他のほとんどの正規表現フレーバーとは異なり、繰り返しキャプチャ グループが一致した回数を実際にカウントできます (他のほとんどの正規表現エンジンは単にその情報を破棄します)。文字列の最初のアスタリスク。

その情報は、

match.Groups[1].Captures.Count

(もちろん、これは「最初のアスタリスクの前にスラッシュがない」と「アスタリスクがまったくない」の両方がスコア0を取得することを意味します。これは、質問で求めているように見えますが、なぜそうなるのかわかりませんわかる)

于 2013-04-20T06:45:31.373 に答える
1

タスクにアプローチする方法:

  1. すべてのテスト パスを検証します (それらが有効であり、\*\または で終わることを確認します*)。

  2. 並べ替えられたコレクションを使用して、テスト パスと関連するアクションを追跡します。

  3. 文字列内のワイルドカードの位置に基づいてコレクションを並べ替えます。

  4. 並べ替えられたコレクションの各パスに対してアイテムをテストします。文字列の を に
    置き換えて、正規表現で使用できます。*.*?

  5. 最初の一致で停止し、関連するアクションを返します。それ以外の場合は、コレクション内の次のテストを続行します。

上記のいくつかの簡単なテスト実装:

void Main()
{
    // Define some actions to test and add them to a collection
    var ActionPaths = new List<ActionPath>() {
        new ActionPath() {TestPath = "/foo/*/baz",   Action = "include"},
        new ActionPath() {TestPath = "/foo/bar/*",   Action = "exclude"},
        new ActionPath() {TestPath = "/foo/doo/boo", Action = "exclude"},
    };
    // Sort the list of actions based on the depth of the wildcard
    ActionPaths.Sort();

    // the path for which we are trying to find the corresponding action
    string PathToTest = "/foo/bar/baz";

    // Test all ActionPaths from the top down until we find something
    var found = default(ActionPath);
    foreach (var ap in ActionPaths) {
        if (ap.IsMatching(PathToTest)) {
            found = ap;
            break;
        }
    }

    // At this point, we have either found an Action, or nothing at all
    if (found != default(ActionTest)) {
        // Found an Action!
    } else {
        // Found nothing at all :-(
    }
}

// Hold and Action Test
class ActionPath : IComparable<ActionPath>
{
    public string TestPath;
    public string Action;

    // Returns true if the given path matches the TestPath
    public bool IsMatching(string path) {
        var t = TestPath.Replace("*",".*?");
        return Regex.IsMatch(path, "^" + t + "$");
    }

    // Implements IComparable<T>
    public int CompareTo(ActionPath other) {
       if (other.TestPath == null) return 1;
       var ia = TestPath.IndexOf("*");
       var ib = other.TestPath.IndexOf("*");
       if (ia < ib) return 1;       
       if (ia > ib) return -1;
       return 0;
   }
}
于 2013-04-20T01:22:21.730 に答える