Регулярное выражение для выбора запятых вне кавычек

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

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

Например:

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

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

Мне действительно не нужны одиночные или двойные кавычки.

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

Ответ 1

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

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

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

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

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

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

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

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

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

Ответ 2

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

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

DEMO

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

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

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

DEMO


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

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

DEMO

Ответ 3

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

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

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

Ответ 4

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

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

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

Ответ 5

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

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

Это также позволяет использовать строки типа "'foo\'bar' => 'bar\\',".

Ответ 6

Ответ 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()]);
}