簡體   English   中英

需要一些正則表達幫助

[英]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創建的,而不是由與組匹配的正則表達式創建的。 請參見方法TokenizeTokenizeLine 他們努力工作。

  1. 分割(線和空格)
  2. 匹配(如果是Vsan或Interface)


拆分后,它變得非常簡單。 只需向前移動令牌並創建VSanInterface對象即可。
令牌的順序是字符串組的順序(由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。 您可以在代碼中使用此模型來獲取所需的信息。

  1. 通過使用對象模型,您可以隨時更改分析,而無需更改業務邏輯中的任何內容。
  2. 解析邏輯比Regex更簡單易懂
  3. 可能存在可讀異常(用於用戶輸入)
  4. 您可以在轉換期間解析int / boos aso
  5. 您的同事可以處理和維護您的代碼。

請問我是否有其他問題,我很樂意為您服務! 還請給我反饋,我願意接受新的印象!

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM