Regex для выбора запятых вне кавычек - PullRequest
36 голосов
/ 11 марта 2009

Я не совсем уверен, возможно ли это, поэтому я обращаюсь к вам.

Я хотел бы найти регулярное выражение, которое выберет все запятые, которые выходят за пределы наборов кавычек.

Например:

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

Это выберет одну запятую в строке 1 после 'bar',

Меня не волнуют одинарные и двойные кавычки.

У кого-нибудь есть мысли? Я чувствую, что это может быть возможно с readaheads, но мое регулярное выражение фу слишком слаб.

Ответы [ 6 ]

82 голосов
/ 11 марта 2009

Это будет соответствовать любой строке вплоть до первого не заключенного в кавычки ",". Это то, что вы хотите?

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

Если вы хотите, чтобы все из них (и в качестве контр-примера парню, который сказал, что это невозможно), вы можете написать:

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

, который будет соответствовать всем им. Таким образом

'test, a "comma,", bob, ",sam,",here'.gsub(/(,)(?=(?:[^"]|"[^"]*")*$)/,';')

заменяет все запятые , а не внутри кавычек на точки с запятой и выдает:

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

Если вам нужно, чтобы он работал через разрывы строк, просто добавьте флаг m (multiline).

10 голосов
/ 28 августа 2014

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

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

DEMO

ИЛИ (только PCRE)

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

"[^"]*" соответствует всему блоку в двойных кавычках. То есть на этом входе buz,"bar,foo" это регулярное выражение будет соответствовать только "bar,foo". Теперь следующий (*SKIP)(*F) делает совпадение неудачным. Затем он переходит к шаблону, который был рядом с символом |, и пытается сопоставить символы из оставшейся строки. То есть в нашем выводе , рядом с шаблоном | будет соответствовать только запятая, которая была сразу после buz. Обратите внимание, что это не будет соответствовать запятой, которая присутствовала в двойных кавычках, потому что мы уже пропускаем часть с двойными кавычками.

DEMO


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

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

DEMO

2 голосов
/ 05 апреля 2015

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

Эта функция разбивает строку на запятые, но не на те, которые находятся в одинарных или двойных кавычках. Он может быть легко расширен дополнительными символами для использования в качестве кавычек (хотя для пар символов, таких как «» потребуется еще несколько строк кода), и даже скажет вам, если вы забыли закрыть кавычку в ваших данных:

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
1 голос
/ 10 мая 2011

@ SocialCensus, пример, который вы дали в комментарии к MarkusQ, где вы добавляете «рядом с», не работает с примером, который MarkusQ дал выше, что если мы изменим sam на sam's : (тест, "запятая", bob, ", sam's,", здесь) не имеет соответствия с (,) (? = (?: [^ "'] | [" |'] [ ^ "'] ") $). На самом деле, сама проблема "меня не интересуют одинарные и двойные кавычки", неоднозначна. Вы должны четко понимать, что вы имеете в виду, цитируя либо с "или с". Например, разрешено ли вложение? Если да, то на сколько уровней? Если только 1 вложенный уровень, что происходит с запятой вне внутренней вложенной цитаты, но внутри внешней вложенной цитаты? Вы также должны учитывать, что одиночные кавычки сами по себе случаются как апострофы (то есть, как контрпример, который я привел ранее с Сэмом). Наконец, сделанное вами регулярное выражение на самом деле не обрабатывает одинарные кавычки наравне с двойными кавычками, поскольку предполагает, что последний тип кавычки обязательно является двойной кавычкой - и замена последней двойной кавычки на ['| "] также имеет проблему если текст не содержит правильных кавычек (или если используются апострофы), я полагаю, мы могли бы предположить, что все кавычки правильно очерчены.

Регулярное выражение MarkusQ отвечает на вопрос: найдите все запятые, которые имеют четное число двойных кавычек после него (т. Е. Находятся вне двойных кавычек), и не обращайте внимания на все запятые, которые имеют нечетное число двойных кавычек после него (т. Е. Находятся внутри двойных кавычек) цитаты). Как правило, это то же решение, которое вы, вероятно, хотите, но давайте рассмотрим несколько аномалий. Во-первых, если кто-то пропустит кавычку в конце, то это регулярное выражение находит все неправильные запятые, а не находит нужные или не находит ни одного. Конечно, если двойная кавычка отсутствует, все ставки отменяются, так как может быть неясно, принадлежит ли пропущенная в конце или вместо в начале; однако есть законный случай, когда регулярное выражение может потерпеть неудачу (это вторая «аномалия»). Если вы настраиваете регулярное выражение для перехода по текстовым строкам, то вы должны знать, что цитирование нескольких последовательных абзацев требует, чтобы вы помещали одинарную двойную кавычку в начале каждого абзаца и пропускали кавычку в конце каждого абзаца, за исключением конец самого последнего абзаца. Это означает, что в промежутке между этими абзацами регулярное выражение в некоторых местах будет неудачным, а в других - успешным.

Примеры и краткое обсуждение цитирования абзацев и вложенного цитирования можно найти здесь http://en.wikipedia.org/wiki/Quotation_mark.

1 голос
/ 10 мая 2011

Ответ MarkusQ работал прекрасно для меня около года, пока не получилось. Я только что получил ошибку переполнения стека в строке около 120 запятых и 3682 символов. На Java вот так:

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

Вот моя чрезвычайно не элегантная замена, которая не переполняет стек:

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 голос
/ 11 марта 2009

Попробуйте это регулярное выражение:

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

Это также допускает строки типа «'foo\'bar' => 'bar\\',».

...