[C#] 따옴표로 묶지 않은 공백을 구분하는 정규 표현식


Answers

옵션 필요 없음

정규식 :

\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));
Question

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

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

예상 출력 :

  1. 이리
  2. ~이다.
  3. 내 끈
  4. 그것
  5. 있다
  6. 6 경기

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




이 문제에 대한 일반적인 해결책을 무료 오픈 소스 자바 스크립트 객체의 형태로 살펴보고 싶다면 http://splitterjsobj.sourceforge.net/ 을 방문하여 실시간 데모를 볼 수 있습니다 (다운로드). . 이 객체에는 다음과 같은 기능이 있습니다.

  • 사용자 정의 인용 문자 쌍을 사용하여 구분 기호를 이스케이프 (따옴표 안의 분리 방지) 할 수 있습니다. 따옴표는 사용자 정의 이스케이프 문자 및 / 또는 "큰 따옴표 이스케이프"로 이스케이프 처리 할 수 ​​있습니다. 이스케이프 문자는 이스케이프 처리 될 수 있습니다 (자체적으로). 5 개의 출력 배열 중 하나 (객체의 속성)에서 출력은 이스케이프 처리되지 않습니다. 예를 들어 escape char = /, "a ///"b "가 이스케이프 처리되지 않은 경우 / b"
  • 분리 문자 배열로 분할합니다. 한 번의 호출로 파일을 구문 분석합니다. 출력 배열은 중첩됩니다.
  • 자바 스크립트가 인식하는 모든 이스케이프 시퀀스는 분할 프로세스 및 / 또는 전처리 과정에서 평가할 수 있습니다.
  • 콜백 기능
  • 크로스 브라우저 일관성

객체는 jQuery 플러그인으로도 사용할 수 있지만이 사이트의 새 사용자는이 메시지에 하나의 링크 만 포함 할 수 있습니다.




최고 대답은 나를 위해 아주 효과적이지 않습니다. 나는이 종류의 문자열을 공백으로 나누려고했지만 점 ( '.')으로 나뉘는 것처럼 보입니다.

"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"문자 이상을 포착해야했습니다. 문제를 해결하기 위해 Grignio의 대답과 비슷한 정규 표현식을 약간 수정했습니다.

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();



숀,

다음 정규 표현식을 사용해야한다고 생각합니다.

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

문안 인사,
Lieven




Lieven의 솔루션은 그곳에있는 대부분의 방법을 얻었으며 그의 의견에 Bartek의 솔루션으로 결말을 바꾸는 문제 일뿐입니다. 최종 결과는 다음과 같이 작동합니다.

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

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

산출:

  1. 이리
  2. ~이다.
  3. "내 끈"
  4. 그것
  5. 있다
  6. "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'



이 정규식은 따옴표 나 여분의 공백을 제거하지 않지만 위에 주어진 경우를 기반으로 분할되므로 문자열에 대한 후 처리를 원할 수 있습니다. 이렇게하면 따옴표 붙은 문자열을 올바르게 유지해야합니다.

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



편집 : 내 이전 게시물 죄송합니다, 이것은 분명히 가능합니다.

영숫자가 아닌 문자를 모두 처리하려면 다음과 같은 것이 필요합니다.

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

당신은 .Net> 2.0을 사용한다면 foreach를 더 똑똑하게 만들 수 있습니다.




코드 프로젝트에서 LSteinle의 " 텍스트 한정자를 지원하는 분할 함수 "살펴보기

관심이있는 그의 프로젝트에서 발췌 한 내용입니다.

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);
}

호출 할 때마다 Regex 문을 작성하고 컴파일하는 루프를 호출하는 것에주의하십시오. 그래서 좀 더 많은 시간을 필요로한다면 Regex 캐시를 만들 것입니다.




약간의 혼란 스러움을 제외하면 정규 언어는 따옴표의 짝수 / 홀수 계산을 추적 할 수 있지만 데이터에 이스케이프 된 따옴표 (\ ")가 포함될 수 있으면 제대로 처리 할 정규 표현식을 생성하거나 이해하는 것이 실제 문제입니다 .