Разделить на запятую, но только если не в скобках - PullRequest
6 голосов
/ 19 февраля 2011

Я пытаюсь разделить строку с запятой

my $string='ab,12,20100401,xyz(A,B)';
my @array=split(',',$string);

Если я делю разделение, как указано выше, массив будет иметь значения

ab
12
20100401
xyz(A,
B)

Мне нужны значения, как показано ниже.

ab
12
20100401
xyz(A,B) 

(не следует разбивать xyz (A, B) на 2 значения) Как мне это сделать?

Ответы [ 6 ]

4 голосов
/ 19 февраля 2011
use Text::Balanced qw(extract_bracketed);
my $string = "ab,12,20100401,xyz(A,B(a,d))";
my @params = ();
while ($string) {
    if ($string =~ /^([^(]*?),/) {
        push @params, $1;
        $string =~ s/^\Q$1\E\s*,?\s*//;
    } else {
        my ($ext, $pre);
        ($ext, $string, $pre) = extract_bracketed($string,'()','[^()]+');
        push @params, "$pre$ext";
        $string =~ s/^\s*,\s*//;
    }
}

Этот поддерживает:

  • вложенные скобки;
  • пустые поля;
  • строки любой длины.
3 голосов
/ 19 февраля 2011

Вот один из способов, который должен работать.

use Regexp::Common;

my $string = 'ab,12,20100401,xyz(A,B)';
my @array = ($string =~ /(?:$RE{balanced}{-parens=>'()'}|[^,])+/g);

Regexp :: Common можно установить из CPAN.

В этом коде есть ошибка,исходя из глубины регулярных выражений :: Common.Имейте в виду, что это (к сожалению) не будет соответствовать отсутствию места между ,,.

1 голос
/ 19 февраля 2011

Ограничить количество элементов, которые можно разделить на:

split(',', $string, 4)
0 голосов
/ 23 июня 2017

Ну, старый вопрос, но я просто столкнулся с этим всю ночь, и вопрос так и не был отмечен как отвеченный, так что если кто-то приедет сюда от Google, как я, то вот что я наконец-то получил.Это очень короткий ответ, использующий только встроенные функции регулярного выражения PERL:

my $string='ab,12,20100401,xyz(A,B)';
string =~ 's/((\((?>[^)(]*(?2)?)*\))|[^,()]*)(*SKIP)([,])/$1\n/g';
my @array=split('\n',$string);

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

Предполагается, что у вас не будет символов новой строки \n в начальном значении $ string.Если вам нужно, либо временно замените их чем-то еще до строки подстановки, а затем используйте цикл, чтобы заменить обратно после split, или просто выберите другой разделитель для разделения массива.

0 голосов
/ 19 февраля 2011

Вот моя попытка.Он должен хорошо обрабатывать глубину и даже может быть расширен, чтобы легко включать другие символы в скобках (хотя сложнее быть уверенным, что они соответствуют).Этот метод обычно не работает для кавычек, а не для скобок.

#!/usr/bin/perl

use strict;
use warnings;

my $string='ab,12,20100401,xyz(A(2,3),B)';

print "$_\n" for parse($string);

sub parse {
  my ($string) = @_;
  my @fields;

  my @comma_separated = split(/,/, $string);

  my @to_be_joined;
  my $depth = 0;
  foreach my $field (@comma_separated) {
    my @brackets = $field =~ /(\(|\))/g;
    foreach (@brackets) {
      $depth++ if /\(/;
      $depth-- if /\)/;
    }

    if ($depth == 0) {
      push @fields, join(",", @to_be_joined, $field);
      @to_be_joined = ();
    } else {
      push @to_be_joined, $field;
    }
  }

  return @fields;
}
0 голосов
/ 19 февраля 2011

Вот еще один способ:

my $string='ab,12,20100401,xyz(A,B)';
my @array = ($string =~ /(
    [^,]*\([^)]*\)   # comma inside parens is part of the word
    |
    [^,]*)           # split on comma outside parens
    (?:,|$)/gx);

Производит:

ab
12
20100401
xyz(A,B)
...