Pergunta
Estou usando expressões regulares para tentar corresponder a blocos de seção em um arquivo ini. Estou usando a receita dada no livro Livro de receitas de expressões regulares, mas não parece estar funcionando para mim.
Aqui está o código que estou usando:
final BufferedReader in = new BufferedReader(
new FileReader(file));
String s;
String s2 = "";
while((s = in.readLine())!= null)
s2 += s + System.getProperty("line.separator");
in.close();
final String regex = "^\\[[^\\]\r\n]+](?:\r?\n(?:[^\r\n].*)?)*";
final Pattern pattern = Pattern.compile(regex, Pattern.MULTILINE);
String sectionBlock = null;
final Matcher regexMatcher = pattern.matcher(s2);
if (regexMatcher.find()) {
sectionBlock = regexMatcher.group();
}
Aqui estão o conteúdo do meu arquivo de entrada:
[Section 2]
Key 2.0=Value 2.0
Key 2.2=Value 2.2
Key 2.1=Value 2.1
[Section 1]
Key 1.1=Value 1.1
Key 1.0=Value 1.0
Key 1.2=Value 1.2
[Section 0]
Key 0.1=Value 0.1
Key 0.2=Value 0.2
Key 0.0=Value 0.0
O problema é que sectionBlock
acaba sendo igual ao conteúdo inteiro do arquivo, e não apenas à primeira seção.
(Não sei se isso importa, mas estou fazendo isso no Windows e nos separadores de linha em s2
são iguais a " r n" (pelo menos, é isso que a ideia depurador os exibe como).)
O que eu estou fazendo errado aqui?
Solução
Experimente este regex em vez disso:
(?ms)^\[[^]\r\n]+](?:(?!^\[[^]\r\n]+]).)*
ou o java string literal regex:
"(?ms)^\\[[^]\r\n]+](?:(?!^\\[[^]\r\n]+]).)*"
Uma explicação (curta):
(?ms) // enable multi-line and dot-all matching
^ // the start of a line
\[ // match a '['
[^]\r\n]+ // match any character except '[', '\r' and '\n', one or more times
] // match a ']'
(?: // open non-capturing group 1
(?! // start negative look-ahead
^ // the start of a line
\[ // match a '['
[^]\r\n]+ // match any character except '[', '\r' and '\n', one or more times
] // match a ']'
) // stop negative look-ahead
. // any character (including line terminators)
)* // close non-capturing group 1 and match it zero or more times
Em inglês simples, seria lido como:
Combine um '[' seguido por um ou mais caracteres, exceto '[', ' r' e ' n', seguido por um ']' (vamos chamar essa correspondência x). Então, para cada string vazia no texto, primeiro olhe para a frente para ver se você não vê uma correspondência X, se não o fizer, combine qualquer caractere.
Outras dicas
Você usa o quantificador ganancioso *
Combinando a string mais longa possível. Use o quantificador relutante *?
Em vez disso, obter a correspondência mais curta possível.