[英]Need Some Regular Expression Assistance
試圖匹配包含在一個字符串中的數據:
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);
如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
前面,而字符串中的情況並非如此。
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
最好的解決方案是使用分詞器/解析器來獲取所需的信息。
我認為您無法使用單個Regex來處理它(對其他人有效且透明)。 在我看來,正則表達式並不總是解決復雜字符串問題的方法。
我還認為,大型Regex隨時都無法維護,因此應避免使用。 (自己嘗試,從Internet的任何Page中獲取任何復雜的Regex。不要閱讀,該表達式應該做什么,並嘗試描述該表達式的功能。您會驚訝於作者的期望和期望。要做的表達。
簡單的正則表達式來加粗我的觀點:
這個正則表達式做什么?
(?:[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])+)\])
這正則表達式是執行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
對象即可。
令牌的順序是字符串組的順序(由Tokenize中的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。 您可以在代碼中使用此模型來獲取所需的信息。
請問我是否有其他問題,我很樂意為您服務! 還請給我反饋,我願意接受新的印象!
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.