尝试匹配此数据,该数据包含在一个字符串中:
vsan 1 interfaces:
fc2/1
vsan 10 interfaces:
fc1/1 fc1/2 fc1/3 fc1/4
fc1/5 fc1/6 fc1/7 fc1/8
fc1/9 fc1/10 fc1/11 fc1/12
fc1/13 fc1/14 fc1/15 fc1/16
我得到的输出按每个vsan正确分组,但我只得到每个输出中的第一个接口(fcnn / nn)。例如,在vsan 10中我想要所有接口,但我只获得fc1 / 1 这是我正在使用的正则表达式:
string MemberMatchString =
@"vsan\s(?<number>\d+)[\s]interfaces:\n\s+(?<interfaces>\sfc\d+/\d+)\s+\n?";
MatchCollection MemberList = Regex.Matches(block, MemberMatchString);
答案 0 :(得分:1)
根据 parapura 的建议,我会使用String.Split()
,至少要检索接口:
String block = "vsan 10 interfaces:\nfc1/1 fc1/2 fc1/3\nfc1/4";
String number = Regex.Match(block, @"vsan\s(?<number>\d+)\sinterfaces:").
Groups["number"].Value;
String[] interfaces = block.Substring(block.IndexOf(':') + 2).
Split(new char[] {' '}, StringSplitOptions.RemoveEmptyEntries);
您只获得第一个界面,因为您的正则表达式请求匹配(简化):
vsan X interfaces:
fcX/X
这意味着您希望vsan X interfaces:
出现在每个fcX/X
的前面,而在您的字符串中则不是这样。
答案 1 :(得分:0)
List<string> interfaces = new List<string>();
using (StringReader reader = new StringReader(subjectString))
{
string line;
while ((line = reader.ReadLine()) != null)
{
Regex regexObj = new Regex(@"fc\d+/\d+");
Match matchResults = regexObj.Match(line);
while (matchResults.Success)
{
interfaces.Add(matchResults.Value);
matchResults = matchResults.NextMatch();
}
}
}
foreach (var inter in interfaces) Console.WriteLine("{0}", inter);
输出:
fc1/1
fc1/2
fc1/3
fc1/4
fc1/5
fc1/6
fc1/7
fc1/8
fc1/9
fc1/10
fc1/11
fc1/12
fc1/13
fc1/14
fc1/15
fc1/16
答案 2 :(得分:0)
它最好的解决方案是Tokenizer / Parser来获取您想要的信息。
我认为你不能用一个正则表达式处理它(对其他人有效和透明)。在我看来,正则表达式并不总是复杂字符串问题的解决方案。
我也认为,大型正则表达式在任何时候都是不可维护的,因此应该避免。 (自己尝试一下,从任何来自互联网的页面获取任何复杂的正则表达式。不要阅读,表达式应该做什么,并尝试描述表达式的功能。你会被赋予作者所期望的,以及你所期望的要做的表达。
简单的正则表达式强调我的观点:
这个正则表达式做了什么?
(?:[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*|"(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21\x23-\x5b\x5d-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])*")@(?:(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?|\[(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?|[a-z0-9-]*[a-z0-9]:(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21-\x5a\x53-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])+)\])
此正则表达式是this页面RFC 2822
的实现。
这个是同一页中的缩小版。
[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*@(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?
两者都可用于查看电子邮件地址!你有没有想到这个?
创建一个Tokenzier / Parser:为了向您展示我将如何解决这个问题,我为您准备了一个工作样本。
只需将其粘贴到控制台应用程序,应该可以正常工作:-)
请告诉我有关我的代码的反馈,以及我的帮助是否对您有用。
创建一个Tokenizer,它将表达式拆分为匹配的标记。在这种情况下,令牌派生自接口IToken
标记由Line创建,而不是由正则表达式与组匹配。请参阅方法Tokenize
和TokenizeLine
。他们做了很多努力。
拆分后,它变得非常简单。只需向前移动代币并创建VSan
和Interface
对象
令牌是按字符串组的顺序排序(由令牌中的Regex定义),因此在列表中移动始终是:
VSan
Interface
Interface
Interface
Vsan
Interface
Interface
因此,您可以轻松创建VSan对象并在之后添加所有接口。如果下一个VSan令牌在线,只需创建一个新的VsanObject,继续向新实例添加接口。
现在您有一个Vsans列表,其中包含您可以使用的接口列表
我覆盖了ToString
方法以使结果可见。
public static class Program{
static string VsanString =
@"vsan 1 interfaces:
fc2/1
vsan 10 interfaces:
fc1/1 fc1/2 fc1/3 fc1/4
fc1/5 fc1/6 fc1/7 fc1/8
fc1/9 fc1/10 fc1/11 fc1/12
fc1/13 fc1/14 fc1/15 fc1/16 ";
public static void Main (string[] args) {
VSanTokenizer vSanTokenizer = new VSanTokenizer(VsanString);
IList<IToken> tokens = vSanTokenizer.Tokens;
VsanTokenInterpreter vsanTokenInterpreter = new VsanTokenInterpreter(tokens);
IList<IVSan> vSans = vsanTokenInterpreter.VSans;
foreach (IVSan vSan in vSans) {
Console.WriteLine(vSan.ToString());
}
Console.WriteLine("Please press return to quit.");
Console.ReadLine();
}
}
interface IVSan {
int Number { get; }
IList<IInterface> Interfaces { get; }
}
class VSan : IVSan {
private readonly IList<IInterface> interfaces;
private readonly int number;
public VSan(int number, IList<IInterface> interfaces) {
this.number = number;
this.interfaces = interfaces;
}
public override string ToString() {
StringBuilder toString = new StringBuilder();
toString.Append("Vsan with Number: ");
toString.Append(number);
toString.Append(" has following Interfaces:");
toString.AppendLine("");
foreach (IInterface @interface in Interfaces) {
toString.Append("Intefaces with Name: ");
toString.Append(@interface.Name);
toString.AppendLine("");
}
return toString.ToString();
}
#region Implementation of IVSan
public int Number {
get { return number; }
}
public IList<IInterface> Interfaces {
get { return interfaces; }
}
#endregion
}
interface IInterface {
string Name { get; }
}
class Interface : IInterface {
private readonly string name;
public Interface(string name) {
this.name = name;
}
#region Implementation of IInterface
public string Name {
get { return name; }
}
#endregion
}
interface IToken {
string Value { get; }
}
interface IVsanToken : IToken {
int VsanInterfaceNumber { get; }
}
internal abstract class AbstractToken : IToken {
private readonly string value;
public AbstractToken(string value) {
this.value = value;
}
#region Implementation of IToken
public string Value {
get { return value; }
}
#endregion
}
class VsanToken : AbstractToken, IVsanToken {
private readonly int vsanInterfaceNumber;
public VsanToken(string value)
: base(value) {
vsanInterfaceNumber = int.Parse(value);
}
#region Implementation of IVsanToken
public int VsanInterfaceNumber {
get { return vsanInterfaceNumber; }
}
#endregion
}
class InterfaceToken : AbstractToken, IInterfaceToken {
private readonly int firstNumber;
private readonly int secondNumber;
public InterfaceToken(string value)
: base(value) {
Match match = Regex.Match(value, "fc([0-9])/([0-9]+)");
Group firstNumberGroup = match.Groups[1];
Group secondNumberGroup = match.Groups[2];
firstNumber = int.Parse(firstNumberGroup.Value);
secondNumber = int.Parse(secondNumberGroup.Value);
}
public int SecondNumber {
get { return secondNumber; }
}
public int FirstNumber {
get { return firstNumber; }
}
}
interface IInterfaceToken : IToken {
//Edited: Added Second and FirstNumber to Interface so it can be accessed
int SecondNumber { get; }
int FirstNumber { get ; }
}
class VSanTokenizer {
private readonly string vSanString;
private IList<IToken> tokens;
public VSanTokenizer(string vSanString) {
this.vSanString = vSanString;
tokens = Tokenize(vSanString);
}
public string VSanString {
get { return vSanString; }
}
private IList<IToken> Tokenize(string vSanString) {
List<IToken> tokens = new List<IToken>();
StringReader reader = new StringReader(vSanString);
string readLine = reader.ReadLine();
while (readLine != null) {
IList<IToken> tokenizeLine = TokenizeLine(readLine);
tokens.AddRange(tokenizeLine);
readLine = reader.ReadLine();
}
return tokens;
}
private IList<IToken> TokenizeLine(string readLine) {
IList<IToken> tokens = new List<IToken>();
Match vsanInterfaceDeclartion = Regex.Match(readLine, "vsan ([0-9]+) interfaces:");
if (vsanInterfaceDeclartion.Success) {
Group numberGroup = vsanInterfaceDeclartion.Groups[1];
VsanToken vsanToken = new VsanToken(numberGroup.Value);
tokens.Add(vsanToken);
return tokens;
}
Match vsanInterface = Regex.Match(readLine, "(fc[0-9]/[0-9]+)");
if (vsanInterface.Success) {
GroupCollection groupCollection = vsanInterface.Groups;
foreach (Group vsanInterfaceGroup in groupCollection) {
string value = vsanInterfaceGroup.Value;
IToken token = new InterfaceToken(value);
tokens.Add(token);
}
}
return tokens;
}
public IList<IToken> Tokens {
get {
return tokens;
}
}
}
class VsanTokenInterpreter {
private readonly IList<IToken> tokens;
private readonly IList<IVSan> vSans;
public VsanTokenInterpreter(IList<IToken> tokens) {
this.tokens = tokens;
this.vSans = ParseTokens(tokens);
}
private IList<IVSan> ParseTokens(IList<IToken> tokens) {
IList<IVSan> vsans = new List<IVSan>();
IVSan currentVSan = null;
foreach (IToken token in tokens) {
if (token is IVsanToken) {
currentVSan = CreateVSan((IVsanToken)token);
vsans.Add(currentVSan);
} else if (token is IInterfaceToken) {
if (currentVSan == null)
throw new Exception("First Vsan Line has to be declared!");
IInterface inter = CreateInterface((IInterfaceToken)token);
currentVSan.Interfaces.Add(inter);
}
}
return vsans;
}
protected virtual IInterface CreateInterface(IInterfaceToken interfaceToken) {
//Edited: you can now access the First/Second Number from the Interface Token and use it to create the Instance of your interface:
int firstNumber = interfaceToken.FirstNumber;
int secondNumber = interfaceToken.SecondNumber;
return new Interface(interfaceToken.Value);
}
protected virtual IVSan CreateVSan(IVsanToken vsanToken) {
return new VSan(vsanToken.VsanInterfaceNumber, new List<IInterface>());
}
public IList<IVSan> VSans {
get { return vSans; }
}
public IList<IToken> Tokens {
get { return tokens; }
}
}
结果你得到一个包含IInterfaces的IVsan。您可以在代码中使用此模型来获取您要查找的信息。
如果您有疑问,请问我,我很乐意帮助您!还请给我反馈,我愿意接受新的印象!