在格式化字符串中提取一些值
Extract some values in formatted string
我想检索格式如下的字符串中的值:
public var any:int = 0;
public var anyId:Number = 2;
public var theEnd:Vector.<uint>;
public var test:Boolean = false;
public var others1:Vector.<int>;
public var firstValue:CustomType;
public var field2:Boolean = false;
public var secondValue:String = "";
public var isWorks:Boolean = false;
我想在自定义中存储字段名称、类型和值 class 属性 :
public class Property
{
public string Name { get; set; }
public string Type { get; set; }
public string Value { get; set; }
}
并使用正则表达式获取这些值。
我该怎么办?
谢谢
编辑:我试过了,但我不知道如何进一步使用矢量..等等
/public var ([a-zA-Z0-9]*):([a-zA-Z0-9]*)( = \"?([a-zA-Z0-9]*)\"?)?;/g
看来,您不需要正则表达式;在一个简单的情况下
正如您提供的那样:
String text =
@"public var any:int = 0;
public var anyId:Number = 2;
public var theEnd:Vector.<uint>;
public var test:Boolean = false;
public var others1:Vector.<int>;
public var firstValue:CustomType;
public var field2:Boolean = false;";
List<Property> result = text
.Split(new Char[] {'\r','\n'}, StringSplitOptions.RemoveEmptyEntries)
.Select(line => {
int varIndex = line.IndexOf("var") + "var".Length;
int columnIndex = line.IndexOf(":") + ":".Length;
int equalsIndex = line.IndexOf("="); // + "=".Length;
// '=' can be absent
equalsIndex = equalsIndex < 0 ? line.Length : equalsIndex + "=".Length;
return new Property() {
Name = line.Substring(varIndex, columnIndex - varIndex - 1).Trim(),
Type = line.Substring(columnIndex, columnIndex - varIndex - 1).Trim(),
Value = line.Substring(equalsIndex).Trim(' ', ';')
};
})
.ToList();
如果文本可以包含评论和其他工作人员,例如
"public (*var is commented out*) var sample: int = 123;;;; // another comment"
你必须实现一个解析器
好的,发布我基于正则表达式的答案。
您的正则表达式 - /public var ([a-zA-Z0-9]*):([a-zA-Z0-9]*)( = \"?([a-zA-Z0-9]*)\"?)?;/g
- 包含正则表达式定界符,它们在 C# 中不受支持,因此被视为文字符号。您需要删除它们和修饰符 g
,因为要在 C# Regex.Matches
或 Regex.Match
与 while
和 Match.Success
/.NextMatch()
中获得多个匹配项可以使用。
我使用的正则表达式是 (?<=\s*var\s*)(?<name>[^=:\n]+):(?<type>[^;=\n]+)(?:=(?<value>[^;\n]+))?
。包含换行符作为否定字符 classes 可以匹配换行符。
var str = "public var any:int = 0;\r\npublic var anyId:Number = 2;\r\npublic var theEnd:Vector.<uint>;\r\npublic var test:Boolean = false;\r\npublic var others1:Vector.<int>;\r\npublic var firstValue:CustomType;\r\npublic var field2:Boolean = false;\r\npublic var secondValue:String = \"\";\r\npublic var isWorks:Boolean = false;";
var rx = new Regex(@"(?<=\s*var\s*)(?<name>[^=:\n]+):(?<type>[^;=\n]+)(?:=(?<value>[^;\n]+))?");
var coll = rx.Matches(str);
var props = new List<Property>();
foreach (Match m in coll)
props.Add(new Property(m.Groups["name"].Value,m.Groups["type"].Value, m.Groups["value"].Value));
foreach (var item in props)
Console.WriteLine("Name = " + item.Name + ", Type = " + item.Type + ", Value = " + item.Value);
或使用 LINQ:
var props = rx.Matches(str)
.OfType<Match>()
.Select(m =>
new Property(m.Groups["name"].Value,
m.Groups["type"].Value,
m.Groups["value"].Value))
.ToList();
以及 class 示例:
public class Property
{
public string Name { get; set; }
public string Type { get; set; }
public string Value { get; set; }
public Property()
{}
public Property(string n, string t, string v)
{
this.Name = n;
this.Type = t;
this.Value = v;
}
}
性能说明:
正则表达式不是最快的,但肯定比另一个答案中的正则表达式好。这是在 regexhero.net:
执行的测试
您可以使用以下模式:
\s*(?<vis>\w+?)\s+var\s+(?<name>\w+?)\s*:\s*(?<type>\S+?)(\s*=\s*(?<value>\S+?))?\s*;
匹配一行中的每个元素。在量词后附加 ?
会导致非贪婪匹配,这使得模式更简单 - 无需否定所有不需要的 类。
值是可选的,因此值组包含在另一个可选组中 (\s*=\s*(?<value>\S+?))?
使用RegexOptions.Multiline
选项意味着我们不必担心意外匹配换行符。
下例中的 C# 6 语法不是必需的,但多行字符串文字和内插字符串可使代码更简洁。
var input= @"public var any:int = 0;
public var anyId:Number = 2;
public var theEnd:Vector.<uint>;
public var test:Boolean = false;
public var others1:Vector.<int>;
public var firstValue:CustomType;
public var field2:Boolean = false;
public var secondValue:String = """";
public var isWorks:Boolean = false;";
var pattern= @"\s*(?<vis>\w+?)\s+var\s+(?<name>\w+?)\s*:\s*(?<type>\S+?)(\s*=\s*(?<value>\S+?))?\s*;"
var regex = new Regex(pattern, RegexOptions.Multiline);
var results=regex.Matches(input);
foreach (Match m in results)
{
var g = m.Groups;
Console.WriteLine($"{g["name"],-15} {g["type"],-10} {g["value"],-10}");
}
var properties = (from m in results.OfType<Match>()
let g = m.Groups
select new Property
{
Name = g["name"].Value,
Type = g.["type"].Value,
Value = g["value"].Value
})
.ToList();
不过,如果我必须解析更复杂的输入或者有多个模式需要匹配,我会考虑使用像 ANTLR 这样的解析器生成器。学习如何编写语法需要一些时间,但是一旦你学会了它,就很容易创建可以匹配需要非常复杂的正则表达式的输入的解析器。空白管理也变得容易很多
在这种情况下,语法可能类似于:
property : visibility var name COLON type (EQUALS value)? SEMICOLON;
visibility : ALPHA+;
var : ALPHA ALPHA ALPHA;
name : ALPHANUM+;
type : (ALPHANUM|DOT|LEFT|RIGHT);
value : ALPHANUM
| literal;
literal : DOUBLE_QUOTE ALPHANUM* DOUBLE_QUOTE;
ALPHANUM : ALPHA
| DIGIT;
ALPHA : [A-Z][a-z];
DIGIT : [0-9];
...
WS : [\r\n\s] -> skip;
使用解析器,添加 eg 注释就像在 property
规则中的 SEMICOLON
之前添加 comment
一样简单,并添加一个新的 comment
规则来匹配评论模式
我想检索格式如下的字符串中的值:
public var any:int = 0;
public var anyId:Number = 2;
public var theEnd:Vector.<uint>;
public var test:Boolean = false;
public var others1:Vector.<int>;
public var firstValue:CustomType;
public var field2:Boolean = false;
public var secondValue:String = "";
public var isWorks:Boolean = false;
我想在自定义中存储字段名称、类型和值 class 属性 :
public class Property
{
public string Name { get; set; }
public string Type { get; set; }
public string Value { get; set; }
}
并使用正则表达式获取这些值。
我该怎么办?
谢谢
编辑:我试过了,但我不知道如何进一步使用矢量..等等
/public var ([a-zA-Z0-9]*):([a-zA-Z0-9]*)( = \"?([a-zA-Z0-9]*)\"?)?;/g
看来,您不需要正则表达式;在一个简单的情况下 正如您提供的那样:
String text =
@"public var any:int = 0;
public var anyId:Number = 2;
public var theEnd:Vector.<uint>;
public var test:Boolean = false;
public var others1:Vector.<int>;
public var firstValue:CustomType;
public var field2:Boolean = false;";
List<Property> result = text
.Split(new Char[] {'\r','\n'}, StringSplitOptions.RemoveEmptyEntries)
.Select(line => {
int varIndex = line.IndexOf("var") + "var".Length;
int columnIndex = line.IndexOf(":") + ":".Length;
int equalsIndex = line.IndexOf("="); // + "=".Length;
// '=' can be absent
equalsIndex = equalsIndex < 0 ? line.Length : equalsIndex + "=".Length;
return new Property() {
Name = line.Substring(varIndex, columnIndex - varIndex - 1).Trim(),
Type = line.Substring(columnIndex, columnIndex - varIndex - 1).Trim(),
Value = line.Substring(equalsIndex).Trim(' ', ';')
};
})
.ToList();
如果文本可以包含评论和其他工作人员,例如
"public (*var is commented out*) var sample: int = 123;;;; // another comment"
你必须实现一个解析器
好的,发布我基于正则表达式的答案。
您的正则表达式 - /public var ([a-zA-Z0-9]*):([a-zA-Z0-9]*)( = \"?([a-zA-Z0-9]*)\"?)?;/g
- 包含正则表达式定界符,它们在 C# 中不受支持,因此被视为文字符号。您需要删除它们和修饰符 g
,因为要在 C# Regex.Matches
或 Regex.Match
与 while
和 Match.Success
/.NextMatch()
中获得多个匹配项可以使用。
我使用的正则表达式是 (?<=\s*var\s*)(?<name>[^=:\n]+):(?<type>[^;=\n]+)(?:=(?<value>[^;\n]+))?
。包含换行符作为否定字符 classes 可以匹配换行符。
var str = "public var any:int = 0;\r\npublic var anyId:Number = 2;\r\npublic var theEnd:Vector.<uint>;\r\npublic var test:Boolean = false;\r\npublic var others1:Vector.<int>;\r\npublic var firstValue:CustomType;\r\npublic var field2:Boolean = false;\r\npublic var secondValue:String = \"\";\r\npublic var isWorks:Boolean = false;";
var rx = new Regex(@"(?<=\s*var\s*)(?<name>[^=:\n]+):(?<type>[^;=\n]+)(?:=(?<value>[^;\n]+))?");
var coll = rx.Matches(str);
var props = new List<Property>();
foreach (Match m in coll)
props.Add(new Property(m.Groups["name"].Value,m.Groups["type"].Value, m.Groups["value"].Value));
foreach (var item in props)
Console.WriteLine("Name = " + item.Name + ", Type = " + item.Type + ", Value = " + item.Value);
或使用 LINQ:
var props = rx.Matches(str)
.OfType<Match>()
.Select(m =>
new Property(m.Groups["name"].Value,
m.Groups["type"].Value,
m.Groups["value"].Value))
.ToList();
以及 class 示例:
public class Property
{
public string Name { get; set; }
public string Type { get; set; }
public string Value { get; set; }
public Property()
{}
public Property(string n, string t, string v)
{
this.Name = n;
this.Type = t;
this.Value = v;
}
}
性能说明:
正则表达式不是最快的,但肯定比另一个答案中的正则表达式好。这是在 regexhero.net:
执行的测试您可以使用以下模式:
\s*(?<vis>\w+?)\s+var\s+(?<name>\w+?)\s*:\s*(?<type>\S+?)(\s*=\s*(?<value>\S+?))?\s*;
匹配一行中的每个元素。在量词后附加 ?
会导致非贪婪匹配,这使得模式更简单 - 无需否定所有不需要的 类。
值是可选的,因此值组包含在另一个可选组中 (\s*=\s*(?<value>\S+?))?
使用RegexOptions.Multiline
选项意味着我们不必担心意外匹配换行符。
下例中的 C# 6 语法不是必需的,但多行字符串文字和内插字符串可使代码更简洁。
var input= @"public var any:int = 0;
public var anyId:Number = 2;
public var theEnd:Vector.<uint>;
public var test:Boolean = false;
public var others1:Vector.<int>;
public var firstValue:CustomType;
public var field2:Boolean = false;
public var secondValue:String = """";
public var isWorks:Boolean = false;";
var pattern= @"\s*(?<vis>\w+?)\s+var\s+(?<name>\w+?)\s*:\s*(?<type>\S+?)(\s*=\s*(?<value>\S+?))?\s*;"
var regex = new Regex(pattern, RegexOptions.Multiline);
var results=regex.Matches(input);
foreach (Match m in results)
{
var g = m.Groups;
Console.WriteLine($"{g["name"],-15} {g["type"],-10} {g["value"],-10}");
}
var properties = (from m in results.OfType<Match>()
let g = m.Groups
select new Property
{
Name = g["name"].Value,
Type = g.["type"].Value,
Value = g["value"].Value
})
.ToList();
不过,如果我必须解析更复杂的输入或者有多个模式需要匹配,我会考虑使用像 ANTLR 这样的解析器生成器。学习如何编写语法需要一些时间,但是一旦你学会了它,就很容易创建可以匹配需要非常复杂的正则表达式的输入的解析器。空白管理也变得容易很多
在这种情况下,语法可能类似于:
property : visibility var name COLON type (EQUALS value)? SEMICOLON;
visibility : ALPHA+;
var : ALPHA ALPHA ALPHA;
name : ALPHANUM+;
type : (ALPHANUM|DOT|LEFT|RIGHT);
value : ALPHANUM
| literal;
literal : DOUBLE_QUOTE ALPHANUM* DOUBLE_QUOTE;
ALPHANUM : ALPHA
| DIGIT;
ALPHA : [A-Z][a-z];
DIGIT : [0-9];
...
WS : [\r\n\s] -> skip;
使用解析器,添加 eg 注释就像在 property
规则中的 SEMICOLON
之前添加 comment
一样简单,并添加一个新的 comment
规则来匹配评论模式