匹配出现在控制字符之前的字符,如果控制字符不存在则匹配零
本文关键字:控制字符 如果 不存在 字符 | 更新日期: 2023-09-27 18:10:01
我正在研究允许用户为文件夹层次结构中的项目指定"通配符"路径以及当项目匹配该路径时将执行的相关操作的功能。例如:
Path Action
----------- -------
1. $/foo/*/baz include
2. $/foo/bar/* exclude
在上面的例子中,位于$/foo/bar/baz
的物品将匹配这两个动作。考虑到这一点,我想提供通配符路径特异性的粗略分数,这将基于第一个通配符出现的"深度"。最具深度的路径将获胜。重要的是,只有以正斜杠(/*/
)为界的*
被允许作为通配符(除非在末尾然后是/*
),并且可以在路径的各个点指定任何数字。
TL;博士;
所以,我认为在第一个*
之前计算正斜杠数量的正则表达式是可行的。但是,由于多种原因,当路径中没有通配符时,正斜杠的匹配将为零。我得到了以下消极的回顾:
(?<!'*.*)/
在有通配符的情况下工作得很好(例如2个斜杠匹配上面的路径#1,3个斜杠匹配上面的路径#2),但是当没有通配符时,它自然地匹配所有的正斜杠。我相信这是一个简单的步骤来匹配没有,但由于生锈的正则表达式技能,我卡住了。
理想情况下,从学术的角度来看,我想看看是否一个单一的正则表达式可以捕捉到这一点,但奖金点提供了一个更优雅的解决方案的问题!
这是一种方法:
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
的分数)中没有星号,则此正则表达式将无法匹配。如果正则表达式匹配,则可以确保其中至少有一个星号。
现在的聪明之处是,. net正则表达式与大多数其他正则表达式不同,实际上可以计算重复捕获组匹配的次数(大多数其他正则表达式引擎只是丢弃该信息),这允许我们确定字符串中第一个星号之前的斜杠的数量。
该信息可在
中找到match.Groups[1].Captures.Count
(当然这意味着"在第一个星号之前没有斜杠"answers"根本没有星号"都会得到分数0
,这似乎是你在你的问题中所要求的,但我不确定为什么这会有意义)
处理任务的方法:
-
验证所有测试路径(确保它们是有效的,并且包含
'*'
或以*
结束) -
使用已排序的集合来跟踪测试路径和相关的操作。
-
根据通配符在字符串中的位置对集合进行排序。
-
根据已排序集合中的每个路径测试项。
您可以将字符串中的*
替换为.*?
以在正则表达式中使用它。 -
在第一个匹配处停止并返回相关操作,否则继续进行集合中的下一个测试。
上面部分内容的快速测试实现:
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;
}
}
这里不需要正则表达式。
对于LINQ,它是一个双行:
string s = "$/foo/bar/baz";
var asteriskPos = s.IndexOf('*'); // will be -1 if there is no asterisk
var slashCount = s.Where((c, i) => c == '/' && i < asteriskPos).Count();