Как проанализировать строку с разделителями-запятыми, если в поле есть запятая и скобка - PullRequest
2 голосов
/ 29 марта 2011

У меня есть эта строка в C #

adj_con(CL2,1,3,0),adj_cont(CL1,1,3,0),NG, NG/CL, 5 value of CL(JK), HO

Я хочу использовать RegEx для его анализа, чтобы получить следующее:

adj_con(CL2,1,3,0)
adj_cont(CL1,1,3,0)
NG
NG/CL
5 value of CL(JK)
HO

В дополнение к вышеприведенному примеру я проверил следующее, но все еще не могу разобрать его правильно.

"%exc.uns: 8 hours let  @ = ABC, DEF", "exc_it = 1 day"  , " summ=graffe ", " a,b,(c,d)" 

Новый текст будет в одной строке

string mystr = @"""%exc.uns: 8 hours let  @ = ABC, DEF"", ""exc_it = 1 day""  , "" summ=graffe "", "" a,b,(c,d)"""; 

Ответы [ 9 ]

3 голосов
/ 29 марта 2011
string str = "adj_con(CL2,1,3,0),adj_cont(CL1,1,3,0),NG, NG/CL, 5 value of CL(JK), HO";
var resultStrings = new List<string>();
int? firstIndex = null;
int scopeLevel = 0;
for (int i = 0; i < str.Length; i++)
{
    if (str[i] == ',' && scopeLevel == 0)
    {
        resultStrings.Add(str.Substring(firstIndex.GetValueOrDefault(), i - firstIndex.GetValueOrDefault()));
        firstIndex = i + 1;
    }
    else if (str[i] == '(') scopeLevel++;
    else if (str[i] == ')') scopeLevel--;
}
resultStrings.Add(str.Substring(firstIndex.GetValueOrDefault()));
2 голосов
/ 29 марта 2011

Событие быстрее:

([^,]*\x28[^\x29]*\x29|[^,]+)

Это должно сработать. По сути, ищите «отпечаток функции» или что-нибудь без запятой.

adj_con(CL2,1,3,0),adj_cont(CL1,1,3,0),NG, NG/CL, 5 value of CL(JK), HO
                  ^                   ^  ^      ^                  ^

Символ каретки символизирует место, где заканчивается группировка.

1 голос
/ 31 августа 2011

Еще один способ реализовать то, что делал Snowbear:

    public static string[] SplitNest(this string s, char src, string nest, string trg)
    {
        int scope = 0;
        if (trg == null || nest == null) return null;
        if (trg.Length == 0 || nest.Length < 2) return null;
        if (trg.IndexOf(src) >= 0) return null;
        if (nest.IndexOf(src) >= 0) return null;

        for (int i = 0; i < s.Length; i++)
        {
            if (s[i] == src && scope == 0)
            {
                s = s.Remove(i, 1).Insert(i, trg);
            }
            else if (s[i] == nest[0]) scope++;
            else if (s[i] == nest[1]) scope--;
        }

        return s.Split(trg);
    }

Идея состоит в том, чтобы заменить любой не вложенный разделитель другим разделителем, который затем можно использовать обычным string.Split().Вы также можете выбрать тип используемого кронштейна - (), <>, [] или даже что-то странное, например \/, ][ или `'.Для ваших целей вы должны использовать

string str = "adj_con(CL2,1,3,0),adj_cont(CL1,1,3,0),NG, NG/CL, 5 value of CL(JK), HO";
string[] result = str.SplitNest(',',"()","~");

Функция сначала превратит вашу строку в

adj_con(CL2,1,3,0)~adj_cont(CL1,1,3,0)~NG~ NG/CL~ 5 value of CL(JK)~ HO

, а затем разделит на ~, игнорируя вложенные запятые.

1 голос
/ 29 марта 2011

Если вы просто должны использовать Regex, тогда вы можете разбить строку на следующее:

,                # match a comma
(?=              # that is followed by
  (?:            # either
    [^\(\)]*     #  no parens at all
    |            # or
    (?:          #  
      [^\(\)]*   #  ...
      \(         #  (
      [^\(\)]*   #     stuff in parens
      \)         #  )
      [^\(\)]*   #  ...
    )+           #  any number of times
  )$             # until the end of the string
)

Это разбивает ваш ввод на следующее:

adj_con(CL2,1,3,0)
adj_cont(CL1,1,3,0)
NG
NG/CL
5 value of CL(JK)
HO

Вы также можете использоватьСбалансированная группировка .NET создает версию, которая работает с вложенными паренами, но вы, вероятно, также хорошо справляетесь с одним из решений не-Regex.

1 голос
/ 29 марта 2011

Только это регулярное выражение:

[^,()]+(\([^()]*\))?

Тестовый пример:

var s= "adj_con(CL2,1,3,0),adj_cont(CL1,1,3,0),NG, NG/CL, 5 value of CL(JK), HO";
Regex regex = new Regex(@"[^,()]+(\([^()]*\))?");
var matches = regex.Matches(s)
    .Cast<Match>()
    .Select(m => m.Value);

возвращает

adj_con(CL2,1,3,0)
adj_cont(CL1,1,3,0)
NG
 NG/CL
 5 value of CL(JK)
 HO
0 голосов
/ 30 марта 2011

Вот более сильный вариант, который разбирает весь текст, включая вложенные скобки:

string pattern = @"
\A
(?>
    (?<Token>
        (?:
            [^,()]              # Regular character
            |
            (?<Paren> \( )      # Opening paren - push to stack
            |
            (?<-Paren> \) )     # Closing paren - pop
            |
            (?(Paren),)         # If inside parentheses, match comma.
        )*?
    )
    (?(Paren)(?!))    # If we are not inside parentheses,
    (?:,|\Z)          # match a comma or the end
)*? # lazy just to avoid an extra empty match at the end,
    #  though it removes a last empty token.
\Z
";
Match match = Regex.Match(data, pattern, RegexOptions.IgnorePatternWhitespace);

Вы можете получить все совпадения, перебрав match.Groups["Token"].Captures.

0 голосов
/ 29 марта 2011

Класс TextFieldParser ( msdn ), кажется, имеет встроенную функциональность:

TextFieldParser Class: - Предоставляет методы и свойства для разбора структурированных текстовых файлов.

Анализ текстового файла с помощью TextFieldParser аналогичен итерации по текстовому файлу, а метод ReadFields для извлечения текстовых полей аналогичен разбиению строк.

TextFieldParser может анализировать файлы двух типов: с разделителями или с фиксированной шириной. Некоторые свойства, такие как Delimiters и HasFieldsEnclosedInQuotes, имеют смысл только при работе с файлами с разделителями, а свойство FieldWidths имеет смысл только при работе с файлами фиксированной ширины.

См. статью , которая помогла мне найти, что

0 голосов
/ 29 марта 2011
var s = "adj_con(CL2,1,3,0),adj_cont(CL1,1,3,0),NG, NG/CL, 5 value of CL(JK), HO";  
var result = string.Join(@"\n",Regex.Split(s, @"(?<=\)),|,\s"));  

Шаблон соответствует) и исключает его из совпадения, затем сопоставляет или сопоставляет, а затем пробел.

result =

adj_con (CL2,1,3,0)
adj_cont (CL1,1,3,0)
NG
NG / CL
5 значение CL (JK)
HO

0 голосов
/ 29 марта 2011

Предполагая, что не вложенные, совпадающие скобки, вы можете легко сопоставить нужные токены вместо разделения строки:

MatchCollection matches = Regex.Matches(data, @"(?:[^(),]|\([^)]*\))+");
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...