Como obtenho a substring " It's big \"problem "
usando uma expressão regular?
s = ' function(){ return " It\'s big \"problem "; }';
Como obtenho a substring " It's big \"problem "
usando uma expressão regular?
s = ' function(){ return " It\'s big \"problem "; }';
Respostas:
/"(?:[^"\\]|\\.)*"/
Trabalha no The Regex Coach e no PCRE Workbench.
Exemplo de teste em JavaScript:
var s = ' function(){ return " Is big \\"problem\\", \\no? "; }';
var m = s.match(/"(?:[^"\\]|\\.)*"/);
if (m != null)
alert(m);
(?:...)
é um grupo passivo ou não captador. Isso significa que não pode ser referenciado posteriormente mais tarde.
/(["'])(?:[^\1\\]|\\.)*?\1/
var s = ' my \\"new\\" string and \"this should be matched\"';
, essa abordagem levará a resultados inesperados.
Este é um exemplo de nanorc.sample disponível em muitas distribuições linux. É usado para destacar a sintaxe de seqüências de caracteres de estilo C
\"(\\.|[^\"])*\"
var s = ' my \\"new\\" string and \"this should be matched\"';
, essa abordagem levará a resultados inesperados.
" \"(\\\\.|[^\\\"])*\" "
Conforme fornecido pelo ePharaoh, a resposta é
/"([^"\\]*(\\.[^"\\]*)*)"/
Para que o descrito acima se aplique a cadeias simples ou duplas, use
/"([^"\\]*(\\.[^"\\]*)*)"|\'([^\'\\]*(\\.[^\'\\]*)*)\'/
A maioria das soluções fornecidas aqui usa caminhos alternativos de repetição, como (A | B) *.
Você pode encontrar estouros de pilha em entradas grandes, pois algum compilador de padrões implementa isso usando recursão.
Java, por exemplo: http://bugs.java.com/bugdatabase/view_bug.do?bug_id=6337993
Algo assim:
"(?:[^"\\]*(?:\\.)?)*"
ou o fornecido por Guy Bedford reduzirá a quantidade de etapas de análise, evitando a maioria dos estouros de pilha.
/"(?:[^"\\]++|\\.)*+"/
Retirado diretamente de man perlre
um sistema Linux com o Perl 5.22.0 instalado. Como uma otimização, esse regex usa a forma 'posessiva' de ambos +
e *
para impedir o retorno, pois é sabido de antemão que uma sequência sem uma citação de fechamento não corresponderia em nenhum caso.
/(["\']).*?(?<!\\)(\\\\)*\1/is
deve funcionar com qualquer string entre aspas
Este funciona perfeitamente no PCRE e não cai com o StackOverflow.
"(.*?[^\\])??((\\\\)+)?+"
Explicação:
"
;.*?
{Lazy match}; terminando com caractere sem escape [^\\]
;(.*?[^\\])??
"
), mas pode ser precedida de um número par de pares de sinais de escape (\\\\)+
; e é Greedy (!) opcional: ((\\\\)+)?+
{Correspondência Greedy}, a seqüência de caracteres pode estar vazia ou sem pares finais!"(.*?[^\\])?(\\\\)*"
aqui está um que funciona com "e" e você adiciona outros facilmente no início.
("| ') (?: \\\ 1 | [^ \ 1]) *? \ 1
ele usa a referência anterior (\ 1) corresponde exatamente ao que está no primeiro grupo ("ou ').
[^\1]
deve ser substituída por, .
porque não existe uma referência anti-retorno e isso não importa. a primeira condição sempre corresponderá antes que algo ruim possa acontecer.
[^\1]
com .
efetivamente mudar esta regex para ("|').*?\1
e em seguida, ele iria corresponder "foo\"
no "foo \" bar"
. Dito isto, [^\1]
é realmente difícil trabalhar. @ Mathiashansen - Você é melhor fora com o complicado e caro (?!\1).
(para o todo regex, com alguma limpeza eficiência, seria (["'])(?:\\.|(?!\1).)*+\1
A. +
É opcional se o seu motor não apoiá-lo.
Uma opção que não foi abordada antes é:
Isso tem o bônus adicional de poder corresponder corretamente as tags abertas com escape.
Digamos que você tenha a seguinte string; String \"this "should" NOT match\" and "this \"should\" match"
Aqui, \"this "should" NOT match\"
não deve ser correspondido e "should"
deve ser. Além disso this \"should\" match
, isso deve corresponder e \"should\"
não.
Primeiro um exemplo.
// The input string.
const myString = 'String \\"this "should" NOT match\\" and "this \\"should\\" match"';
// The RegExp.
const regExp = new RegExp(
// Match close
'([\'"])(?!(?:[\\\\]{2})*[\\\\](?![\\\\]))' +
'((?:' +
// Match escaped close quote
'(?:\\1(?=(?:[\\\\]{2})*[\\\\](?![\\\\])))|' +
// Match everything thats not the close quote
'(?:(?!\\1).)' +
'){0,})' +
// Match open
'(\\1)(?!(?:[\\\\]{2})*[\\\\](?![\\\\]))',
'g'
);
// Reverse the matched strings.
matches = myString
// Reverse the string.
.split('').reverse().join('')
// '"hctam "\dluohs"\ siht" dna "\hctam TON "dluohs" siht"\ gnirtS'
// Match the quoted
.match(regExp)
// ['"hctam "\dluohs"\ siht"', '"dluohs"']
// Reverse the matches
.map(x => x.split('').reverse().join(''))
// ['"this \"should\" match"', '"should"']
// Re order the matches
.reverse();
// ['"should"', '"this \"should\" match"']
Ok, agora para explicar o RegExp. Este é o regexp pode ser facilmente dividido em três partes. Do seguinte modo:
# Part 1
(['"]) # Match a closing quotation mark " or '
(?! # As long as it's not followed by
(?:[\\]{2})* # A pair of escape characters
[\\] # and a single escape
(?![\\]) # As long as that's not followed by an escape
)
# Part 2
((?: # Match inside the quotes
(?: # Match option 1:
\1 # Match the closing quote
(?= # As long as it's followed by
(?:\\\\)* # A pair of escape characters
\\ #
(?![\\]) # As long as that's not followed by an escape
) # and a single escape
)| # OR
(?: # Match option 2:
(?!\1). # Any character that isn't the closing quote
)
)*) # Match the group 0 or more times
# Part 3
(\1) # Match an open quotation mark that is the same as the closing one
(?! # As long as it's not followed by
(?:[\\]{2})* # A pair of escape characters
[\\] # and a single escape
(?![\\]) # As long as that's not followed by an escape
)
Provavelmente, isso é muito mais claro na forma de imagem: gerado usando o Regulex de Jex
Imagem no github (JavaScript Regular Expression Visualizer.) Desculpe, não tenho uma reputação suficientemente alta para incluir imagens; portanto, é apenas um link no momento.
Aqui está um exemplo de uma função de exemplo usando esse conceito um pouco mais avançado: https://gist.github.com/scagood/bd99371c072d49a4fee29d193252f5fc#file-matchquotes-js
É preciso lembrar que os regexps não são uma bala de prata para tudo que é y. Algumas coisas são mais simples de fazer com um cursor e linear, manual, buscando. Uma CFL faria o truque de maneira bastante trivial, mas não há muitas implementações de CFL (afaik).
Uma versão mais extensa do https://stackoverflow.com/a/10786066/1794894
/"([^"\\]{50,}(\\.[^"\\]*)*)"|\'[^\'\\]{50,}(\\.[^\'\\]*)*\'|“[^”\\]{50,}(\\.[^“\\]*)*”/
Esta versão também contém
“
e fechar ”
)Se for pesquisado desde o início, talvez isso possa funcionar?
\"((\\\")|[^\\])*\"
Eu enfrentei um problema semelhante ao tentar remover as seqüências de caracteres citadas que podem interferir na análise de alguns arquivos.
Acabei com uma solução em duas etapas que supera qualquer regex complicado que você possa criar:
line = line.replace("\\\"","\'"); // Replace escaped quotes with something easier to handle
line = line.replaceAll("\"([^\"]*)\"","\"x\""); // Simple is beautiful
Mais fácil de ler e provavelmente mais eficiente.
Se o seu IDE for IntelliJ Idea, você poderá esquecer todas essas dores de cabeça e armazenar sua regex em uma variável String e, ao copiar e colar dentro da aspas duplas, ela mudará automaticamente para um formato aceitável para regex.
exemplo em Java:
String s = "\"en_usa\":[^\\,\\}]+";
agora você pode usar essa variável no seu regexp ou em qualquer outro lugar.