programing tip

따옴표가 아닌 경우 공백으로 분할 할 정규식

itbloger 2020. 11. 15. 10:58
반응형

따옴표가 아닌 경우 공백으로 분할 할 정규식


.Net Regex.Split 메서드를 사용하여이 입력 문자열을 배열로 분할하고 싶습니다. 따옴표로 묶지 않으면 공백으로 분할해야합니다.

입력 : 여기에 "내 문자열"이 있으며 "6 개 일치"가 있습니다.

예상 출력 :

  1. 여기
  2. 이다
  3. 내 문자열
  4. 그것
  5. 있다
  6. 여섯 경기

어떤 패턴이 필요합니까? 또한 RegexOptions를 지정해야합니까?


옵션이 필요하지 않습니다.

정규식 :

\w+|"[\w\s]*"

씨#:

Regex regex = new Regex(@"\w+|""[\w\s]*""");

또는 "문자를 제외해야하는 경우 :

    Regex
        .Matches(input, @"(?<match>\w+)|\""(?<match>[\w\s]*)""")
        .Cast<Match>()
        .Select(m => m.Groups["match"].Value)
        .ToList()
        .ForEach(s => Console.WriteLine(s));

Lieven의 솔루션은 대부분의 방법을 사용하며, 그의 의견에서 언급했듯이 Bartek 솔루션의 결말을 변경하는 문제 일뿐입니다. 최종 결과는 다음과 같은 정규식입니다.

(?<=")\w[\w\s]*(?=")|\w+|"[\w\s]*"

입력 : 여기에 "내 문자열"이 있으며 "6 개 일치"가 있습니다.

산출:

  1. 여기
  2. 이다
  3. "내 문자열"
  4. 그것
  5. 있다
  6. "여섯 경기"

불행히도 따옴표가 포함되어 있습니다. 대신 다음을 사용하는 경우 :

(("((?<token>.*?)(?<!\\)")|(?<token>[\w]+))(\s)*)

그리고 다음과 같이 "토큰"일치를 명시 적으로 캡처합니다.

    RegexOptions options = RegexOptions.None;
    Regex regex = new Regex( @"((""((?<token>.*?)(?<!\\)"")|(?<token>[\w]+))(\s)*)", options );
    string input = @"   Here is ""my string"" it has   "" six  matches""   ";
    var result = (from Match m in regex.Matches( input ) 
                  where m.Groups[ "token" ].Success
                  select m.Groups[ "token" ].Value).ToList();

    for ( int i = 0; i < result.Count(); i++ )
    {
        Debug.WriteLine( string.Format( "Token[{0}]: '{1}'", i, result[ i ] ) );
    }

디버그 출력 :

Token[0]: 'Here'
Token[1]: 'is'
Token[2]: 'my string'
Token[3]: 'it'
Token[4]: 'has'
Token[5]: ' six  matches'

최고의 답변은 저에게 효과적이지 않습니다. 이런 종류의 문자열을 공백으로 분할하려고했지만 점 ( '.')으로도 분할 된 것처럼 보입니다.

"the lib.lib" "another lib".lib

나는 질문이 정규식에 대해 묻는 것을 알고 있지만 이것을 수행하기 위해 정규식이 아닌 함수를 작성했습니다.

    /// <summary>
    /// Splits the string passed in by the delimiters passed in.
    /// Quoted sections are not split, and all tokens have whitespace
    /// trimmed from the start and end.
    public static List<string> split(string stringToSplit, params char[] delimiters)
    {
        List<string> results = new List<string>();

        bool inQuote = false;
        StringBuilder currentToken = new StringBuilder();
        for (int index = 0; index < stringToSplit.Length; ++index)
        {
            char currentCharacter = stringToSplit[index];
            if (currentCharacter == '"')
            {
                // When we see a ", we need to decide whether we are
                // at the start or send of a quoted section...
                inQuote = !inQuote;
            }
            else if (delimiters.Contains(currentCharacter) && inQuote == false)
            {
                // We've come to the end of a token, so we find the token,
                // trim it and add it to the collection of results...
                string result = currentToken.ToString().Trim();
                if (result != "") results.Add(result);

                // We start a new token...
                currentToken = new StringBuilder();
            }
            else
            {
                // We've got a 'normal' character, so we add it to
                // the curent token...
                currentToken.Append(currentCharacter);
            }
        }

        // We've come to the end of the string, so we add the last token...
        string lastResult = currentToken.ToString().Trim();
        if (lastResult != "") results.Add(lastResult);

        return results;
    }

Bartek Szabat의 답변을 사용하고 있었지만 토큰에 "\ w"문자 이상을 캡처해야했습니다. 문제를 해결하기 위해 Grzenio의 답변과 유사하게 그의 정규식을 약간 수정했습니다.

Regular Expression: (?<match>[^\s"]+)|(?<match>"[^"]*")

C# String:          (?<match>[^\\s\"]+)|(?<match>\"[^\"]*\")

Bartek의 코드 (따옴표로 묶인 토큰을 반환)는 다음과 같습니다.

Regex
        .Matches(input, "(?<match>[^\\s\"]+)|(?<match>\"[^\"]*\")")
        .Cast<Match>()
        .Select(m => m.Groups["match"].Value)
        .ToList()
        .ForEach(s => Console.WriteLine(s));

답변 의 정규식이 매우 유용하다는 것을 알았습니다 . C #에서 작동하게하려면 MatchCollection 클래스를 사용해야합니다.

//need to escape \s
string pattern = "[^\\s\"']+|\"([^\"]*)\"|'([^']*)'";

MatchCollection parsedStrings = Regex.Matches(line, pattern);

for (int i = 0; i < parsedStrings.Count; i++)
{
    //print parsed strings
    Console.Write(parsedStrings[i].Value + " ");
}
Console.WriteLine();

This regex will split based on the case you have given above, although it does not strip the quotes or extra spaces, so you may want to do some post processing on your strings. This should correctly keep quoted strings together though.

"[^"]+"|\s?\w+?\s

With a little bit of messiness, regular languages can keep track of even/odd counting of quotes, but if your data can include escaped quotes (\") then you're in real trouble producing or comprehending a regular expression that will handle that correctly.


Shaun,

I believe the following regex should do it

(?<=")\w[\w\s]*(?=")|\w+  

Regards,
Lieven


EDIT: Sorry for my previous post, this is obviously possible.

To handle all the non-alphanumeric characters you need something like this:

MatchCollection matchCollection = Regex.Matches(input, @"(?<match>[^""\s]+)|\""(?<match>[^""]*)""");
foreach (Match match in matchCollection)
        {
            yield return match.Groups["match"].Value;
        }

you can make the foreach smarter if you are using .Net >2.0


Take a look at LSteinle's "Split Function that Supports Text Qualifiers" over at Code project

Here is the snippet from his project that you’re interested in.

using System.Text.RegularExpressions;

public string[] Split(string expression, string delimiter, string qualifier, bool ignoreCase)
{
    string _Statement = String.Format("{0}(?=(?:[^{1}]*{1}[^{1}]*{1})*(?![^{1}]*{1}))", 
                        Regex.Escape(delimiter), Regex.Escape(qualifier));

    RegexOptions _Options = RegexOptions.Compiled | RegexOptions.Multiline;
    if (ignoreCase) _Options = _Options | RegexOptions.IgnoreCase;

    Regex _Expression = New Regex(_Statement, _Options);
    return _Expression.Split(expression);
}

Just watch out for calling this in a loop as its creating and compiling the Regex statement every time you call it. So if you need to call it more then a handful of times, I would look at creating a Regex cache of some kind.


If you'd like to take a look at a general solution to this problem in the form of a free, open-source javascript object, you can visit http://splitterjsobj.sourceforge.net/ for a live demo (and download). The object has the following features:

  • Pairs of user-defined quote characters can be used to escape the delimiter (prevent a split inside quotes). The quotes can be escaped with a user-defined escape char, and/or by "double quote escape." The escape char can be escaped (with itself). In one of the 5 output arrays (properties of the object), output is unescaped. (For example, if the escape char = /, "a///"b" is unescaped as a/"b)
  • Split on an array of delimiters; parse a file in one call. (The output arrays will be nested.)
  • All escape sequences recognized by javascript can be evaluated during the split process and/or in a preprocess.
  • Callback functionality
  • Cross-browser consistency

The object is also available as a jQuery plugin, but as a new user at this site I can only include one link in this message.

참고URL : https://stackoverflow.com/questions/554013/regular-expression-to-split-on-spaces-unless-in-quotes

반응형