RegEx: pegando valores entre aspas

Eu tenho um valor como este:

"Foo Bar" "Another Value" something else 

Que regex retornará os valores entre aspas (por exemplo, Foo Bar e Another Value )?

Eu tenho usado o seguinte com grande sucesso:

 (["'])(?:(?=(\\?))\2.)*?\1 

Ele também suporta citações aninhadas.

Para aqueles que querem uma explicação mais profunda de como isso funciona, aqui está uma explicação do usuário efêmero :

([""']) corresponde a uma citação; ((?=(\\?))\2.) Se a barra invertida existir, devorar, e se isso acontecer ou não, combine um caractere; *? coincidir com muitas vezes (não avidamente, para não comer a citação final); \1 corresponde à mesma cotação usada para abertura.

Em geral, o fragment de expressão regular a seguir é o que você está procurando:

 "(.*?)" 

Isso usa o não-ganancioso *? operador para capturar tudo até, mas não incluindo as próximas aspas duplas. Em seguida, você usa um mecanismo específico do idioma para extrair o texto correspondente.

Em Python, você poderia fazer:

 >>> import re >>> string = '"Foo Bar" "Another Value"' >>> print re.findall(r'"(.*?)"', string) ['Foo Bar', 'Another Value'] 

Eu iria para:

 "([^"]*)" 

O [^ “] é regex para qualquer caractere, exceto ‘
A razão pela qual eu uso isso sobre o operador não-ganancioso é que eu tenho que continuar pesquisando para ter certeza de que estou correto.

Vamos ver duas maneiras eficientes que lidam com aspas escapadas. Esses padrões não são projetados para serem concisos nem estéticos, mas para serem eficientes.

Essas formas usam a discriminação de primeiro caractere para localizar rapidamente aspas na string sem o custo de uma alternação. (A idéia é descartar rapidamente caracteres que não sejam citações sem testar os dois ramos da alternância.)

O conteúdo entre aspas é descrito com um loop desenrolado (em vez de uma alternância repetida) para ser mais eficiente também: [^"\\]*(?:\\.[^"\\]*)*

Obviamente, para lidar com cadeias de caracteres que não tenham aspas balanceadas, você pode usar quantificadores possessivos em vez disso: [^"\\]*+(?:\\.[^"\\]*)*+ ou uma solução alternativa para emulá-los, para evitar muito retrocesso. Você pode escolher também que uma parte entre aspas possa ser uma cotação de abertura até a próxima cotação (não escapada) ou o final da string. Neste caso, não há necessidade de usar quantificadores possessivos, você só precisa fazer a última cotação opcional.

Aviso: às vezes aspas não são escapadas com uma barra invertida, mas repetindo a citação. Nesse caso, o subpadrão de conteúdo se parece com isso: [^"]*(?:""[^"]*)*

Os padrões evitam o uso de um grupo de captura e uma referência anterior (quero dizer algo como (["']).....\1 ) e uso uma simples alternância, mas com ["'] no início, em fator.

Perl gosta:

 ["'](?:(?< =")[^"\\]*(?s:\\.[^"\\]*)*"|(?<=')[^'\\]*(?s:\\.[^'\\]*)*') 

(note que (?s:...) é um acréscimo sintático para ativar o modo pontilhado / singleline dentro do grupo sem captura. Se esta syntax não for suportada, você pode facilmente alternar este modo para todo o padrão ou replace o padrão. ponto com [\s\S] )

(A forma como este padrão é escrito é totalmente "dirigida à mão" e não leva em consideração as eventuais otimizações internas do mecanismo)

Script ECMA:

 (?=["'])(?:"[^"\\]*(?:\\[\s\S][^"\\]*)*"|'[^'\\]*(?:\\[\s\S][^'\\]*)*') 

POSIX estendido:

 "[^"\\]*(\\(.|\n)[^"\\]*)*"|'[^'\\]*(\\(.|\n)[^'\\]*)*' 

ou simplesmente:

 "([^"\\]|\\.|\\\n)*"|'([^'\\]|\\.|\\\n)*' 

Uma resposta muito tardia, mas gostaria de responder

 (\"[\w\s]+\") 

http://regex101.com/r/cB0kB8/1

Peculiarmente, nenhuma dessas respostas produz um regex onde a correspondência retornada é o texto dentro das aspas, que é o que é solicitado. O MA-Madden tenta, mas recebe apenas a partida interna como um grupo capturado, em vez de toda a partida. Uma maneira de realmente fazer isso seria:

 (?< =(["']\b))(?:(?=(\\?))\2.)*?(?=\1) 

Exemplos para isso podem ser vistos nesta demonstração https://regex101.com/r/Hbj8aP/1

A chave aqui é o lookbehind no início (o ?< = ) e o lookahead positivo no final (o ?= ). O lookbehind está procurando por trás do personagem atual para checar uma cotação, se for encontrado, então comece a partir daí e então o lookahead está verificando o personagem à frente para uma cotação e se for encontrado, pare naquele personagem. O grupo lookbehind (o ["'] ) é colocado entre parênteses para criar um grupo para qualquer citação que tenha sido encontrada no começo, então é usado no final lookahead (?=\1) para garantir que ele pare quando encontrar a citação correspondente.

A única outra complicação é que, como o lookahead não consome realmente a cotação final, ele será encontrado novamente pela aparência inicial, o que faz com que o texto entre as cotações de finalização e início na mesma linha seja correspondido. Colocar um limite de palavra na citação de abertura ( ["']\b ) ajuda com isso, embora, idealmente, eu gostaria de passar pela frente, mas eu não acho que isso seja possível. O bit que permite caracteres escapados no meio I tirado diretamente da resposta de Adam.

Esta versão

  • contas para citações escapadas
  • controles de retrocesso

     /(["'])((?:(?!\1)[^\\]|(?:\\\\)*\\[^\\])*)\1/ 

O padrão (["'])(?:(?=(\\?))\2.)*?\1 acima faz o trabalho, mas eu estou preocupado com o seu desempenho (não é ruim, mas poderia ser melhor). abaixo é ~ 20% mais rápido.

O padrão "(.*?)" Está incompleto. Meu conselho para todos ler isso é apenas não utilizá-lo !!!

Por exemplo, não é possível capturar muitas cadeias de caracteres (se necessário, posso fornecer um caso de teste exaustivo) como o abaixo:

$ string = ‘Como vai você? Eu estou bem, obrigada ‘;

O resto deles é tão “bom” quanto o acima.

Se você realmente se importa com desempenho e precisão, comece com o seguinte:

/(['"])((\\\1|.)*?)\1/gm

Nos meus testes cobri todas as cordas que encontrei, mas se encontrar algo que não funcione, atualizo-o de bom grado para você.

Verifique meu padrão em um testador de regex on-line .

O RegEx da resposta aceita retorna os valores, incluindo suas aspas: "Foo Bar" e "Another Value" como correspondências.

Aqui estão RegEx que retornam apenas os valores entre aspas (como o questionador estava pedindo):

Apenas aspas duplas (use o valor do grupo de captura # 1):

"(.*?[^\\])"

Apenas aspas simples (use o valor do grupo de captura # 1):

'(.*?[^\\])'

Ambos (use o valor do grupo de captura # 2):

(["'])(.*?[^\\])\1

Todas as citações escapadas e aninhadas de suporte.

Eu gostei da versão mais expansiva do Axeman, mas tive alguns problemas com ela (não combinava por exemplo

 foo "string \\ string" bar 

ou

 foo "string1" bar "string2" 

corretamente, então eu tentei corrigi-lo:

 # opening quote (["']) ( # repeat (non-greedy, so we don't span multiple strings) (?: # anything, except not the opening quote, and not # a backslash, which are handled separately. (?!\1)[^\\] | # consume any double backslash (unnecessary?) (?:\\\\)* | # Allow backslash to escape characters \\. )*? ) # same character as opening quote \1 
 string = "\" foo bar\" \"loloo\"" print re.findall(r'"(.*?)"',string) 

Apenas tente isso, funciona como um encanto !!!

\ indica saltar caracter

MAIS RESPOSTAS! Aqui está a solução que eu usei

\"([^\"]*?icon[^\"]*?)\"

TLDR;
replace o ícone da palavra com o que você está procurando nas citações e voila!


A maneira como isso funciona é que procura a palavra-chave e não se importa com o que mais entre as aspas. POR EXEMPLO:
id="fb-icon"
id="icon-close"
id="large-icon-close"
o regex procura uma marca de cotação "
então ele procura por qualquer grupo possível de letras que não sejam "
até encontrar o icon
e qualquer possível grupo de letras que não seja "
então procura um fechamento "

De Greg H. Consegui criar esse regex para atender às minhas necessidades.

Eu precisava corresponder a um valor específico qualificado por estar entre aspas. Deve ser uma correspondência completa, nenhuma correspondência parcial poderia desencadear um hit

Por exemplo, “teste” não pôde ser igual a “teste2”.

 reg = r"""(['"])(%s)\1""" if re.search(reg%(needle), haystack, re.IGNORECASE): print "winning..." 

Caçador

 echo 'junk "Foo Bar" not empty one "" this "but this" and this neither' | sed 's/[^\"]*\"\([^\"]*\)\"[^\"]*/>\1 

Isso resultará em:> Foo Bar <> <> mas isso <

Aqui eu mostrei a sequência de resultado entre> <> s para maior clareza, também usando a versão não-gananciosa com este comando sed nós primeiro descartamos o lixo antes e depois desse "" e então substituímos isto com a parte entre o "" e cercar isto por>

Para mim trabalhou este:

 |([\'"])(.*?)\1|i 

Eu usei em uma frase como esta:

 preg_match_all('|([\'"])(.*?)\1|i', $cont, $matches); 

e funcionou muito bem.

Se você estiver tentando encontrar strings que tenham apenas um determinado sufixo, como a syntax de ponto, você pode tentar isto:

\"([^\"]*?[^\"]*?)\".localized

Onde .localized é o sufixo.

Exemplo:

print("this is something I need to return".localized + "so is this".localized + "but this is not")

Ele irá capturar "this is something I need to return".localized e "so is this".localized mas não "but this is not" .

Uma resposta suplementar para o subconjunto de codificadores Microsoft VBA usa apenas a biblioteca Microsoft VBScript Regular Expressions 5.5 e isso fornece o seguinte código

 Sub TestRegularExpression() Dim oRE As VBScript_RegExp_55.RegExp '* Tools->References: Microsoft VBScript Regular Expressions 5.5 Set oRE = New VBScript_RegExp_55.RegExp oRE.Pattern = """([^""]*)""" oRE.Global = True Dim sTest As String sTest = """Foo Bar"" ""Another Value"" something else" Debug.Assert oRE.test(sTest) Dim oMatchCol As VBScript_RegExp_55.MatchCollection Set oMatchCol = oRE.Execute(sTest) Debug.Assert oMatchCol.Count = 2 Dim oMatch As Match For Each oMatch In oMatchCol Debug.Print oMatch.SubMatches(0) Next oMatch End Sub 

Ao contrário da resposta de Adam, eu tenho uma resposta simples, mas trabalhada:

 (["'])(?:\\\1|.)*?\1 

E apenas adicione parênteses se você quiser obter o conteúdo entre aspas assim:

 (["'])((?:\\\1|.)*?)\1 

Em seguida, $1 corresponde ao caractere de cotação e $2 corresponde à sequência de conteúdo.

Eu gostei da solução de Eugen Mihailescu para combinar o conteúdo entre aspas, embora permitindo escaping de citações. No entanto, descobri alguns problemas com o escape e descobri o seguinte regex para corrigi-los:

 (['"])(?:(?!\1|\\).|\\.)*\1 

Ele faz o truque e ainda é bastante simples e fácil de manter.

Demonstração (com mais alguns casos de teste; sinta-se à vontade para usá-lo e expandi-lo).


PS: Se você quer apenas o conteúdo entre as aspas no jogo completo ( $0 ), e não tem medo da penalidade de desempenho, use:

 (?< =(['"])\b)(?:(?!\1|\\).|\\.)*(?=\1) 

PPS: Se o seu foco é apenas na eficiência, vá com a solução de Casimir e Hippolyte ; é um bom.