我需要验证要检索的属性名称的用户输入。
例如,用户可以为Windows窗体控件对象键入" Parent.Container" 属性,或只输入" Name" 属性。然后我用反射来获得属性的价值。
我需要检查用户是否输入了 c#property 的合法符号(或者只是合法的单词符号,如\ w),并且此属性也可以是复合的(包含两个或多个用点分隔的单词) )。
我现在有这个,这是一个正确的解决方案吗?
^([\w]+\.)+[\w]+$|([\w]+)
我使用Regex.IsMatch
方法,当我通过"?someproperty" 时,它返回true
,但" \ w"不包括"?"
答案 0 :(得分:2)
不是最好的,但这会奏效。演示here。
^@?[a-zA-Z_]\w*(\.@?[a-zA-Z_]\w*)*$
请注意
*号码0-9
不允许作为第一个字符
* @
仅允许 作为第一个字符,但不允许其他任何地方(编译器会剥离)
* _
是允许的
修改强>
根据您的要求,下面的Regex
会更有用,因为输入属性名称中不需要@
。检查here。
^[a-zA-Z_]\w*(\.[a-zA-Z_]\w*)*$
答案 1 :(得分:2)
我也一直在寻找这个,但是我不知道现有的答案是完整的。经过一番挖掘,这就是我发现的东西。
首先,我们需要知道想要哪个有效:根据运行时间有效还是根据语言有效?例子:
Foo\u0123Bar
是C#语言的有效属性名称,而不是 runtime 的有效属性名称。差异由编译器平滑处理,编译器将标识符安静地转换为FooģBar
。 @
前缀),该语言将@
视为标识符的一部分,但运行时看不到它。根据您的需求,任何一种都可以。如果要将经过验证的文本输入到反射方法(例如GetProperty(string)
)中,则需要 runtime 有效版本。但是,如果您希望C#开发人员更熟悉的语法,则需要语言-有效版本。
C#版本5是(截至7/2018)具有正式标准的最新版本:ECMA 334规范。它的规则是:
此子节中给出的标识符规则完全对应 除Unicode标准附件15建议的内容外, 下划线可以用作初始字符(如 C语言),Unicode转义序列允许在 标识符,并且允许使用“ @”字符作为前缀来启用 用作标识符的关键字。
提到的“ Unicode标准附件15”为Unicode TR 15, Annex 7,将基本模式形式化为:
<identifier> ::= <identifier_start> ( <identifier_start> | <identifier_extend> )*
<identifier_start> ::= [{Lu}{Ll}{Lt}{Lm}{Lo}{Nl}]
<identifier_extend> ::= [{Mn}{Mc}{Nd}{Pc}{Cf}]
{花括号中的代码}是Unicode类,它们直接通过\p{category}
映射到Regex。因此(经过一些简化),根据 runtime 检查“有效”的基本正则表达式为:
@"^[\p{L}\p{Nl}_][\p{Cf}\p{L}\p{Mc}\p{Mn}\p{Nd}\p{Nl}\p{Pc}]*$"
C#规范还要求标识符采用Unicode规范化形式C。但是,不需要编译器实际执行它。至少Roslyn C#编译器允许使用非规范形式的标识符(例如E\u0304\u0306
),并将其与等效的规范形式的标识符(例如\u0100\u0306
)区别对待。而且,据我所知,没有一种用正则表达式来代表这样的规则的理智方法。如果您不需要/希望用户能够区分看起来完全相同的属性,我的建议是仅对用户输入运行string.Normalize()
即可完成操作。
C#规范说,如果两个标识符仅在格式化字符方面有所不同,则它们是等效的。例如,Elmo
(四个字符)和Elmo
(El\u00ADmo
)是相同的标识符。 (请注意:这是软连字符,通常不可见;但是某些字体可能会显示出来。)如果不可见字符的存在会给您带来麻烦,则可以从正则表达式中删除\p{Cf}
。这并不会减少您接受的标识符,而只是减少您接受的格式。
C#规范保留包含“ __”的标识符供自己使用。根据您的需要,您可能希望排除该可能性。这可能是与正则表达式分开的操作。
Reflection,Type
,IL和其他地方有时会显示类名或带有额外符号的方法名。例如,类型名称可以指定为X`1+Y[T]
。多余的东西不是标识符的 部分-这是表示类型信息的不相关方式。
这只是以前的正则表达式,还允许:
@
第一个是微不足道的修改:只需添加@?
。
Unicode转义序列的格式为@"\\[Uu][\dA-Fa-f]{4}"
。我们可能会尝试将它们楔入[
... ]
对中并称其为完成,但是这样做会错误地允许(例如)\u0000
作为标识符。我们需要将转义序列限制为产生其他可接受字符的序列。一种方法是进行预转换以转换转义序列:将所有\\[Uu][\dA-Fa-f]{4}
替换为相应的字符。
因此,将所有内容放在一起,从C#语言的角度检查字符串是否有效:
bool IsValidIdentifier(string input)
{
if (input is null) { throw new ArgumentNullException(); }
// Technically the input must be in normal form C. Implementations aren't required
// to verify that though, so you could remove this check if your runtime doesn't
// mind.
if (!input.IsNormalized())
{
return false;
}
// Convert escape sequences to the characters they represent. The only allowed escape
// sequences are of form \u0000 or \U0000, where 0 is a hex digit.
MatchEvaluator replacer = (Match match) =>
{
string hex = match.Groups[1].Value;
var codepoint = int.Parse(hex, NumberStyles.HexNumber);
return new string((char)codepoint, 1);
};
var escapeSequencePattern = @"\\[Uu]([\dA-Fa-f]{4})";
var withoutEscapes = Regex.Replace(input, escapeSequencePattern, replacer, RegexOptions.CultureInvariant);
withoutEscapes.Dump();
// Now do the real check.
var isIdentifier = @"^@?[\p{L}\p{Nl}_][\p{Cf}\p{L}\p{Mc}\p{Mn}\p{Nd}\p{Nl}\p{Pc}]*$";
return Regex.IsMatch(withoutEscapes, isIdentifier, RegexOptions.CultureInvariant);
}
提问者早已不复存在,但我觉得有义务提供对实际问题的答案:
string[] parts = input.Split();
return parts.Length == 2
&& IsValidIdentifier(parts[0])
&& IsValidIdentifier(parts[1]);
ECMA 334§7.4.3; ECMA 335§I.10; Unicode TR 15 Annex 7
答案 2 :(得分:0)
您在评论中发布的内容几乎是正确的。但它不会检测单个属性,例如&#34; Name&#34;。
^(?:[\w]+\.)*\w+$
按预期工作。刚刚将+更改为*,将组更改为非捕获组,因为您不关心这里的组。