Pegar parte especifica de uma string usando REGEX

36 respostas
java
A

Estou com uma duvida usando Expressões Regulares (Regex)

Como que eu faço para capturar o valor 812.64 dentro dessa frase?

O padrão de inicio pode ser: 1-CURSO, mais eu precisava desconsiderar o restante de palavras até chegar o valor 812.64.

String frase = “1-CURSO T VOLTA NOT IN NM 24 33.86 812.64 T”;

36 Respostas

P

frase = frase.replaceAll(".*(\\d{1,}\\.\\d{2}).*","$1");

A

@PedreiroDeSoftware vi que vc pegou o padrão de 3 números e 2 casas decimais, só que esqueci de falar que a quantidades desses números mudam, esse valor da frase 812,64 tem lugares no meu arquivo que é outro número, exemplo tem lugar que é 2815,67 ou 115443,82, como fazer pra ele pegar dessa forma ?

P

frase = frase.replaceAll(".*(\\d{1,}\\.\\d{2}).*","$1"); essa regex pega números no formato numero.numero;
Se o formato é numero,numero a regex deve ser ajustada para:
frase = frase.replaceAll(".*(\\d{1,},d{2}).*","$1");
Ocorre que quando você for fazer o parse, deve trocar a virgula por ponto.
ex: frase.replace(",",".");
Para a procura desejada, você deve usar pattern com o intúito de mapear o início e o fim de cata match referente à expressão regular, e usar o subString(inicio, fim) para pegar o resultado.

O que posso recomendar é apenas que estude, pode começar por aqui:

A

@PedreiroDeSoftware to estudando direto, ja vi esse video muito bom, mais tem coisas que esta difícil de entender rssrs.

frase = frase.replaceAll(".(\d{1,},d{2}).","$1");
Dessa forma que vc passou ela esta pegando a frase inteira, tem como vc me ajudar só nessa questão de eu pegar a numeração completa independente da quantidade de números ?

P

Faltou um escape no segundo d:". *(\\d{1,},\\d{2}).* "

Mas olha ai o proposto:

public void testeRegex() {
        String target = "exemplo tem lugar que é 2815,67 ou 115443,82, como fazer pra ele pegar";
        Pattern padrao = Pattern.compile("\\d{1,},\\d{2}");
        Matcher matcher = padrao.matcher(target);
        while (matcher.find()) {            
            System.out.println(target.substring(matcher.start(), matcher.end()));
        }      
    }
}

A

@PedreiroDeSoftware eu entendi oque vc fez, só que a minha dificuldade esta no exemplo que te passei da minha frase.
Na minha frase tem outros números que não quero pegar.
E os números que quero pegar da minha frase mudam de acordo com o arquivo que estou lendo, tem vez que os ultimos valores são 812.64 ou 44852.64 ou 4456812.64 ou etc…
Frase: 1-CURSO T VOLTA NOT IN NM 24 3333.86 812.64 T
Frase: 1-CURSO T VOLTA NOT IN NM 24 31353.86 44852.64 T
Frase: 1-CURSO T VOLTA NOT IN NM 24 335443.86 4456812.64 T

A minha dificuldade é ignorar toda a minha frase e pegar só a última numeração que pode ser o 812.64, 44852.64, 4456812.64 ou outro qualquer…
Antes da numeração que quero pegar tem outros numeros q mudam de tamanho tb.
A minha regex precisa pega só essa ultima numeração completa independente da quantidade de números…
Lembrando que na minha frase tem a palavra 1-CURSO e eu queria manter essa palavra na minha regex para eu localizar essa frase dentro do meu arquivo que estou lendo, consegue me ajudar?

P

Apague o $1 em:

public void testeRegex() {
        String target = "Frase: 1-CURSO T VOLTA NOT IN NM 24 3333.86 812.64 T\n"
                + "Frase: 1-CURSO T VOLTA NOT IN NM 24 31353.86 44852.64 T\n"
                + "Frase: 1-CURSO T VOLTA NOT IN NM 24 335443.86 4456812.64 T";
        String regex = "(\\d{1,}-CURSO).*( \\d{1,}\\.\\d{2}) T";
        String filter;
        Pattern padrao = Pattern.compile(regex);
        Matcher matcher = padrao.matcher(target);
        while (matcher.find()) {
            filter = target.substring(matcher.start(), matcher.end());
            System.out.println(filter.replaceAll(regex, "$1 $2"));
        }
    }

Mantenha o $1.

Regex trabalha com reconhecimento de padrões.
Você tem que observar o padrão da sequência.

A

@PedreiroDeSoftware funcionou direitinho, só que veio outra questão, tem vezes que o número que estou pegando, ele é muito grande e acaba tendo mais de um .(ponto) na numeração, exemplo 1.185.10 ou 22.345.45 ou 122.345.45, nesse caso ele só esta considerando o primeiro número e os 2 últimos, e não completo, como resolver essa questão?

P

Se o padrão for mantido, use split:

while (matcher.find()) {
            String[] split = target.substring(matcher.start(), matcher.end()).split(" ");
            System.out.println(split[0]+" "+split[8]);
        }
A

@PedreiroDeSoftware o padrão é o mesmo, mais usando esse split ele não esta retornando valor nenhum.

Consegue me ajudar nessa tb?

P
public void testeRegex() {
        String target = "Frase: 1-CURSO T VOLTA NOT IN NM 24 3333.86 812.64 T\n"
                + "Frase: 1-CURSO T VOLTA NOT IN NM 24 31353.86 44.852.64 T\n"
                + "Frase: 1-CURSO T VOLTA NOT IN NM 24 3358443.86 4.456.812.64 T";
        //a regex não está boa mas pega o valor, para garantir tem que comparar o tamanho do número com a quantidade de pontos
        String regex = "(\\d{1,}-CURSO).*( \\d{1,}[\\.\\d]*\\.\\d{2}) T";
        String filter;
        Pattern padrao = Pattern.compile(regex);
        Matcher matcher = padrao.matcher(target);
        while (matcher.find()) {
            filter = target.substring(matcher.start(), matcher.end());
            System.out.println(filter.replaceAll(regex, "$1 $2"));
        }
    }

A

@PedreiroDeSoftware Deu certo…mano muito obrigado pela sua ajuda, vou estudar mais, pois essa parada é muito louca de entender rsrs, muito obrigado mesmo, Deus te abençõe…

A

@PedreiroDeSoftware com esse seu código como eu faço para guardar os valores dentro de uma variável?

estou tentando aqui e esta dando erro, pode me ajudar?

P

Use um ArrayList, pois você está pegando mais de um valor.

ArrayList<String> resultados = new ArrayList<>();//fora do método testeRegex;

while (matcher.find()) {
            filter = target.substring(matcher.start(), matcher.end());
            resultados.add(filter.replaceAll(regex, "$1 $2"));
        }
A

@PedreiroDeSoftware me tira uma dúvida quando eu pego só o valor para jogar em uma variável, o valor esta vindo com um espaço antes, exemplo ( 567,44), como faço para retirar esse espaço?

olha o erro: Unparseable number: " 812.64"

P

while(num.charAt(0) == ’ '){num = num.subString(1);}

A

@PedreiroDeSoftware Estou tentando converter um valor exemplo 110.045,42 de string para NumberFormat

Estou fazendo dessa forma abaixo, só que quando o valor é convertido ele esta vindo sem as casas decimais, tipo 110.045. como resolver isso?

NumberFormat n1 = NumberFormat.getInstance();
valor = n1.parse(numnovo).doubleValue();

P

Isso se dá porque hora o documento tem vírgula, hora tem ponto e a regex foi calibrada pra ponto.
Deve resolver.

public void testeRegex() {
        ...
        String regex = "(\\d{1,}-CURSO).*( \\d{1,}[\\.\\d]*[\\.,]\\d{2}) T";
        ...
        }
    }
A

@PedreiroDeSoftware o documento ja foi convertido todas as virgulas para ponto, o problema esta acontecendo quando eu converto esse valor q esta em string para numberformat pois ele esta vindo sem as casas decimais,

P

A conversão está errada.

A regex captura as casas decimais após o último ponto ou virgula.

public void testeRegex() {
    String target = "Frase: 1-CURSO T VOLTA NOT IN NM 24 3333.86 812,64 T\n"
            + "Frase: 1-CURSO T VOLTA NOT IN NM 24 31353.86 44.852.64 T\n"
            + "Frase: 1-CURSO T VOLTA NOT IN NM 24 3358443.86 4.456.812,64 T";
    String regex = "(\\d{1,}-CURSO).* (\\d{1,}[\\.\\d]*[\\.,]\\d{2}) T";
    String filter;
    Pattern padrao = Pattern.compile(regex);
    Matcher matcher = padrao.matcher(target);
    while (matcher.find()) {
        filter = target.substring(matcher.start(), matcher.end());
        System.err.println(filter);
        System.out.println(filter.replaceAll(regex, "$1 $2"));
    }
}

Corrigido na regex.
Não é mais necessário:

A

@PedreiroDeSoftware no meu aqui não deu certo essa última regex, pois ele ta capturando outro valor agora…coloquei uma foto para vc ver como esta a minha e oq esta acontecendo, o valor de 1.185 que foi impresso é referente a conversão de string para NumberFormat e o [812.64, 1.185.10] é da string, precisa converter para NumberFormat com as casas decimais…

A

@PedreiroDeSoftware essa foto esta completa aonde aparece a conversaõ de virgula para ponto

P

Você extrai certo e formata errado.
Revise o parse.

Sem parse:

public void testeRegex() {
        String target = "Frase: 1-CURSO T VOLTA NOT IN NM 24 3333.86 812,64 T\n"
                + "Frase: 1-CURSO T VOLTA NOT IN NM 24 31353.86 44.852.64 T\n"
                + "Frase: 1-CURSO T VOLTA NOT IN NM 24 3358443.86 4.456.812,64 T";
        String regex = "(\\d{1,}-CURSO).* (\\d{1,}[\\.\\d]*[\\.,]\\d{2}) T";
        Pattern padrao = Pattern.compile(regex);
        Matcher matcher = padrao.matcher(target);
        while (matcher.find()) {
            StringBuilder numero = new StringBuilder(matcher.group(2).replaceAll("[\\.,]",""));
            numero.insert(numero.length()-2, ".");
            System.out.println(Double.parseDouble(numero.toString()));
        }
    }

A

@PedreiroDeSoftware Como eu comparo os resultados da minha regex?
Estou fazendo dessa forma na foto e não esta dando certo. Eu estou lendo um arquivo em pdf e os resultados da minha regex são da seguinte forma, exemplo:
1-Curso V Priscila 200,00
1-Curso V Priscila 400,00
1-Curso V Paulo 300,00
1-Curso V Italo 250,00
Estou tentando comparar dessa forma: Se os nomes forem iguais conforme tem no meu exemplo. 1-Curso V Priscila for igual o 1-Curso V Priscila preciso somar para ela os 200,00 + 400,00.
Se os nomes não forem iguais cada um fica com o seu valor,
Tentei de várias formas e não consegui fazer essa comparação. como faço para comparar as regex?

P

Abra outro tópico.
Vc pode usar um Map<String, List<Double>>;
Use o map.putIfAbsent(nome, new ArrayList<>()); para acumular as entradas.
Use o map.get(nome) pra recuperar a lista.
E um for para somar.

P
public void manipulacaoDeDados() {
        String[] linhas = ("1-Curso V Priscila 200,00\n"
                + "1-Curso V Priscila 400,00\n"
                + "1-Curso V Paulo 300,00\n"
                + "1-Curso V Italo 250,00").split("\n");
        Map<String, List<Double>> pessoaEValores = new HashMap<>();
        double valor;
        for (String linha : linhas) {
            String[] colunas = linha.split(" ");
            valor = Double.parseDouble(colunas[3].replace(",", "."));
            pessoaEValores.putIfAbsent(colunas[2], new ArrayList<>());
            pessoaEValores.get(colunas[2]).add(valor);
        }
        pessoaEValores.entrySet()
                .stream()
                .forEach(entry -> somarValores(entry.getKey(), entry.getValue()));
    }
    
    public void somarValores(String nomePessoa, List<Double> values){
        double total = values.stream().mapToDouble(Double::doubleValue).sum();
        System.out.println("Pessoa: "+nomePessoa+", total: "+total);
    }
A

@PedreiroDeSoftware obrigado pela sua ajuda, mais antes eu tinha conseguido fazer com base na sua primeira resposta, só não conseguir entender o porque ele esta retornando 2 valores sendo que estou lendo só um nome igual com dois valores. ( o primeiro é um dos valores que foi somado, o segundo esta correto pois é a soma total), aonde esta o erro?

P

:thinking:, meio sem sentido, pois o map não contém chaves duplicadas.
Imprima o key.length dentro do for que faz a impressão.

A

@PedreiroDeSoftware mesmo usando o key.length(), continua imprimindo dois valores…

P

Tire o for de dentro do while.

A

era isso mesmo, obrigado

A

@PedreiroDeSoftware eu abri um tópico mais ninguém me responde, tem como vc me ajudar em outra questão?

Estou tendo dificuldades para inserir o if e else, .
O código é o seguinte se valorCompra receber algum valor ele vai entrar no if do valor compra, se ele não receber nenhum valor, ele vai retornar nulo ou zero e a mesma coisa o valorVenda, se receber algum valor ele vai entrar no if do valor Venda, se ele não receber nenhum valor, ele vai retornar nulo.

No primeiro if que é o de compra ele esta me retornando o valor correto, mais no if de venda ele não esta retornado nenhum valor, alguém pode me ajudar?

BigDecimal b4 = null;

BigDecimal b10 = null;

BigDecimal b8 = null;

public BigDecimal soma(Double valorCompra, Double valorVenda) {

if (valorCompra == 0) {

BigDecimal b1 = soma0.add(soma1);

BigDecimal b2 = b1.add(soma2);

BigDecimal b3 = b2.add(BigDecimal.valueOf(valorCompra));

b4 = b3.add(BigDecimal.valueOf(correta));

return b4;

} else {
if (valorVenda == 0) {
			BigDecimal b5 = soma0.add(soma1);
			BigDecimal b6 = b5.add(soma2);
			BigDecimal b7 = b6.add(BigDecimal.valueOf(correta));
			b8 = BigDecimal.valueOf(valorVenda).subtract(b7);
			return b8;
		}
			}
	return b10;
}
P

Tem que ter paciência.

A

@PedreiroDeSoftware não entendi muito bem o pq usar o MathContext, no meu caso o MathContext é melhor que Bigdecimal? e com o MathContext eu consigo fazer o if e else e com o Bigdecimal não tem como fazer, seria isso? pois a minha duvida é o porque o if e else não esta funcionando, poderia me dar um exemplo em cima do código?

P

Minha orientação é generalista não é especialista, por isso não conheço bem a classe bigdecimal e não trabalhei com a MathContext.

A

entendi ok, mais obrigado…

Criado 27 de fevereiro de 2020
Ultima resposta 6 de mar. de 2020
Respostas 36
Participantes 2