Wyrażenie regularne do wybierania przecinków poza cudzysłowami

Nie jestem pewien, czy to możliwe, więc zwracam się do ciebie.

Chciałbym znaleźć wyrażenia regularne, które wybiorą wszystkie przecinki, które nie mieszczą się w zestawach cudzysłowów.

Na przykład:

'foo' => 'bar',
'foofoo' => 'bar,bar'

To wyznaczyłoby pojedynczy przecinek w linii 1, po 'bar',

Nie dbam o pojedyncze kontra podwójne cytaty. Czy ktoś ma jakieś przemyślenia? Czuję, że to powinno być możliwe z readaheads, ale mój regex fu jest zbyt słaby.
Author: TheCloudlessSky, 2009-03-11

6 answers

To dopasuje dowolny ciąg znaków do i włącznie z pierwszym nie cytowanym",". Tego właśnie chcesz?

/^([^"]|"[^"]*")*?(,)/

Jeśli chcesz je wszystkie (i jako kontr-przykład dla faceta, który powiedział, że to niemożliwe) możesz napisać:

/(,)(?=(?:[^"]|"[^"]*")*$)/
Który będzie pasował do wszystkich. Tak więc
'test, a "comma,", bob, ",sam,",here'.gsub(/(,)(?=(?:[^"]|"[^"]*")*$)/,';')

Zastępuje wszystkie przecinki nie {[12] } wewnątrz cudzysłowów średnikami i tworzy:

'test; a "comma,"; bob; ",sam,";here'

Jeśli potrzebujesz go do pracy w poprzek linii, po prostu dodaj flagę m (multiline).

 78
Author: MarkusQ,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-03-11 16:32:48

Poniższe wyrażenia regularne pasują do wszystkich przecinków, które są obecne poza podwójnymi cudzysłowami,

,(?=(?:[^"]*"[^"]*")*[^"]*$)

DEMO

Lub(tylko PCRE)

"[^"]*"(*SKIP)(*F)|,

"[^"]*" pasuje do wszystkich podwójnych cytowanych bloków. Oznacza to, że w tym wejściu buz,"bar,foo" regex będzie pasował tylko do "bar,foo". Teraz następująca (*SKIP)(*F) sprawia, że mecz kończy się niepowodzeniem. Następnie przechodzi do wzorca znajdującego się obok symbolu | i próbuje dopasować znaki z pozostałego ciągu. Czyli w naszym dorobku , obok wzorca | będzie pasował tylko przecinek, który był tuż po buz. Zauważ, że to nie będzie pasować do przecinka, który był obecny w podwójnych cudzysłowach, ponieważ już robimy podwójną cytowaną część, aby pominąć.

DEMO


Poniższy regex pasuje do wszystkich przecinków, które są obecne w podwójnych cudzysłowach,

,(?!(?:[^"]*"[^"]*")*[^"]*$)

DEMO

 7
Author: Avinash Raj,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-03-16 13:15:36

Chociaż możliwe jest zhakowanie go za pomocą wyrażeń regularnych (a ja lubię nadużywać wyrażeń regularnych tak samo jak następny facet), prędzej czy później będziesz miał kłopoty próbując obsłużyć podłańcuchy bez bardziej zaawansowanego parsera. Możliwe sposoby na wpadnięcie w kłopoty to mieszane cytaty i unikalne cytaty.

Ta funkcja podzieli łańcuch na przecinki, ale nie te przecinki, które znajdują się w jednym lub podwójnym cytowanym łańcuchu. Można go łatwo rozszerzyć o Dodatkowe znaki do wykorzystania jako cudzysłowy (choć znak pary takie jak "" potrzebowałyby jeszcze kilku linijek kodu), a nawet powiedzą ci, jeśli zapomniałeś zamknąć cytat w swoich danych:

function splitNotStrings(str){
  var parse=[], inString=false, escape=0, end=0

  for(var i=0, c; c=str[i]; i++){ // looping over the characters in str
    if(c==='\\'){ escape^=1; continue} // 1 when odd number of consecutive \
    if(c===','){
      if(!inString){
        parse.push(str.slice(end, i))
        end=i+1
      }
    }
    else if(splitNotStrings.quotes.indexOf(c)>-1 && !escape){
      if(c===inString) inString=false
      else if(!inString) inString=c
    }
    escape=0
  }
  // now we finished parsing, strings should be closed
  if(inString) throw SyntaxError('expected matching '+inString)
  if(end<i) parse.push(str.slice(end, i))
  return parse
}

splitNotStrings.quotes="'\"" // add other (symmetrical) quotes here
 2
Author: Touffy,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-04-05 19:11:44

Spróbuj tego wyrażenia regularnego:

(?:"(?:[^\\"]+|\\(?:\\\\)*[\\"])*"|'(?:[^\\']+|\\(?:\\\\)*[\\'])*')\s*=>\s*(?:"(?:[^\\"]+|\\(?:\\\\)*[\\"])*"|'(?:[^\\']+|\\(?:\\\\)*[\\'])*')\s*,

To pozwala również na ciągi takie jak " 'foo\'bar' => 'bar\\',".

 1
Author: Gumbo,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-03-10 22:45:29

Odpowiedź Markusqa działała dla mnie świetnie przez około rok, aż nie. właśnie dostałem błąd przepełnienia stosu na linii z około 120 przecinkami i 3682 znaków w sumie. W Javie, jak to:

        String[] cells = line.split("[\t,](?=(?:[^\"]|\"[^\"]*\")*$)", -1);

Oto mój niezwykle nieelegancki zamiennik, który nie przepełnia się stosem:

private String[] extractCellsFromLine(String line) {
    List<String> cellList = new ArrayList<String>();
    while (true) {
        String[] firstCellAndRest;
        if (line.startsWith("\"")) {
            firstCellAndRest = line.split("([\t,])(?=(?:[^\"]|\"[^\"]*\")*$)", 2);
        }
        else {
            firstCellAndRest = line.split("[\t,]", 2);                
        }
        cellList.add(firstCellAndRest[0]);
        if (firstCellAndRest.length == 1) {
            break;
        }
        line = firstCellAndRest[1];
    }
    return cellList.toArray(new String[cellList.size()]);
}
 1
Author: sullivan-,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-05-10 01:54:08

@ SocialCensus, przykład, który podałeś w komentarzu do Markusqa, gdzie wrzucasz "obok", nie działa z przykładem, który MarkusQ podał tuż powyżej, że jeśli zmienimy samna Sam ' s: (test, "przecinek",, bob, ",sam ' s,",tutaj) nie ma dopasowania do (,)(?=(?:[^"']|["|'][^"']")$). W rzeczywistości sam problem, "tak naprawdę nie dbam o pojedyncze vs podwójne Cytaty", jest niejednoznaczny. Musisz być jasne, co masz na myśli, cytując albo z "lub z". Na przykład, czy gniazdowanie jest dozwolone czy nie? Jeśli tak, to na ile poziomów? Jeśli tylko 1 zagnieżdżony poziom, co stanie się z przecinkiem poza wewnętrznym zagnieżdżonym cudzysłowem, ale wewnątrz zewnętrznego zagnieżdżonego cudzysłowu? Należy również wziąć pod uwagę, że pojedyncze cudzysłowy występują same w sobie jako apostrofy(np. Wreszcie, Wyrażenie regularne, które zrobiłeś, nie traktuje pojedynczych cudzysłowów na równi z podwójnymi cudzysłowami, ponieważ zakłada, że ostatni typ cudzysłowu jest koniecznie podwójnym cudzysłowem -- i zastąpienie tego ostatniego podwójnego cudzysłowu przez [ | / " ] ma również problem, jeśli tekst nie zawiera poprawnego cytowania (lub jeśli używane są apostrofy), chociaż przypuszczam, że prawdopodobnie moglibyśmy założyć, że wszystkie cytaty są poprawnie określone.

Wyrażenie regularne MarkusQ odpowiada na pytanie: Znajdź wszystkie przecinki, które mają parzystą liczbę podwójnych cudzysłowów po nim (tzn. są poza podwójnymi cudzysłowami) i zignoruj wszystkie przecinki, które mają nieparzystą liczbę podwójnych cudzysłowów po nim (tzn. są wewnątrz podwójnych cudzysłowów). Jest to na ogół to samo rozwiązanie, co prawdopodobnie chcesz, ale spójrzmy na kilka anomalii. Po pierwsze, jeśli ktoś zostawia cudzysłów na końcu, to wyrażenie regularne odnajduje wszystkie niewłaściwe przecinki, zamiast znajdować pożądane lub nie pasować do żadnego. Oczywiście, jeśli brakuje podwójnego cudzysłowu, wszystkie zakłady są wyłączone, ponieważ może nie być jasne, czy brakujący należy na końcu, czy zamiast należy na początku; jednak istnieje przypadek, który jest uzasadniony i gdzie regex może się nie udać (jest to druga "anomalia"). Jeśli dostosujesz Wyrażenie regularne, aby przechodzić przez linie tekstu, powinieneś mieć świadomość, że cytowanie wielu kolejnych akapitów wymaga umieszczenia pojedynczego podwójnego cudzysłowu na początku każdego akapitu i pominięcia cytatu na końcu każdego akapitu, z wyjątkiem końca ostatniego akapitu. Oznacza to, że w przestrzeni tych akapitów wyrażenia regularne ulegną awarii w niektórych miejscach i odniosą sukces w innych.

Przykłady i krótkie dyskusje akapitu cytowanie i cytowanie zagnieżdżone można znaleźć tutaj http://en.wikipedia.org/wiki/Quotation_mark .

 1
Author: Jose_X,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-05-10 11:43:56