Java; Substituição de string (usando expressões regulares)?

128

Como parte de um projeto para a escola, preciso substituir uma sequência do formulário:

5 * x^3 - 6 * x^1 + 1

para algo como:

5x<sup>3</sup> - 6x<sup>1</sup> + 1

Acredito que isso possa ser feito com expressões regulares, mas ainda não sei como fazê-lo.

Você pode me ajudar?

PS: A atribuição real é implementar um aplicativo Java de Polynomial Processing, e estou usando isso para passar polynomial.toString () do modelo para a visualização, e quero exibi-lo usando tags html de uma maneira bonita.

Dan Burzo
fonte
2
Com licença, você pode ser mais específico? Eu não entendo o que você quer dizer.
22909 Dan Burzo
5
Piada velha. codinghorror.com/blog/archives/001016.html tem uma explicação.
Michael Myers
1
Ah :) Acho que realmente li esse artigo há algum tempo ... Então você está sugerindo que o regex não é o caminho a seguir no meu caso?
22909 Dan Burzo
Então, você está permitindo apenas polinômios na forma expandida?
23611 Adam Jaskiewicz

Respostas:

175
str.replaceAll("\\^([0-9]+)", "<sup>$1</sup>");
Can Berk Güder
fonte
ah ... mas você perdeu o colapso do "5 * x" para "5x"
James Curran
Problemas de casal: \ ^ precisa ser \\ ^ e $ precisa ser \ $.
Cdmckay 10/03/09
Ainda estou recebendo o erro "sequência de escape inválida" ... estou perdendo alguma coisa?
22909 Dan Burzo
isso me dá um erro no segundo parâmetro: str.replaceAll ("\\ ^ ([0-9] +)", "<sup> \ $ 1 </sup>"); Eu não entendo isso ... :(
Dan Burzo
2
É possível usar um padrão pré-compilado? Isso pode ser útil se você substituirAll pelo mesmo regex várias vezes.
qed
38
private String removeScript(String content) {
    Pattern p = Pattern.compile("<script[^>]*>(.*?)</script>",
            Pattern.DOTALL | Pattern.CASE_INSENSITIVE);
    return p.matcher(content).replaceAll("");
}
Florian
fonte
8
Este é o melhor IMO, porque usa um Regex compilado, mas o objeto Pattern deve ser um objeto estático.
Marcel Valdez Orozco
O engraçado é que o replaceAllmétodo implica implicitamente Pattern.compile(regex).matcher(testString).replaceAll(regexReplacementString)! Portanto, se você reutilizar o padrão dessa maneira, objetos redundantes serão evitados. Além disso, como diz @MarcelValdezOrozco, torná-lo estático impedirá invocações desnecessárias de compilação de padrões. :)
varun
20
String input = "hello I'm a java dev" +
"no job experience needed" +
"senior software engineer" +
"java job available for senior software engineer";

String fixedInput = input.replaceAll("(java|job|senior)", "<b>$1</b>");
Hubbison
fonte
10
import java.util.regex.PatternSyntaxException;

// (:?\d+) \* x\^(:?\d+)
// 
// Options: ^ and $ match at line breaks
// 
// Match the regular expression below and capture its match into backreference number 1 «(:?\d+)»
//    Match the character “:” literally «:?»
//       Between zero and one times, as many times as possible, giving back as needed (greedy) «?»
//    Match a single digit 0..9 «\d+»
//       Between one and unlimited times, as many times as possible, giving back as needed (greedy) «+»
// Match the character “ ” literally « »
// Match the character “*” literally «\*»
// Match the characters “ x” literally « x»
// Match the character “^” literally «\^»
// Match the regular expression below and capture its match into backreference number 2 «(:?\d+)»
//    Match the character “:” literally «:?»
//       Between zero and one times, as many times as possible, giving back as needed (greedy) «?»
//    Match a single digit 0..9 «\d+»
//       Between one and unlimited times, as many times as possible, giving back as needed (greedy) «+»
try {
    String resultString = subjectString.replaceAll("(?m)(:?\\d+) \\* x\\^(:?\\d+)", "$1x<sup>$2</sup>");
} catch (PatternSyntaxException ex) {
    // Syntax error in the regular expression
} catch (IllegalArgumentException ex) {
    // Syntax error in the replacement text (unescaped $ signs?)
} catch (IndexOutOfBoundsException ex) {
    // Non-existent backreference used the replacement text
}
Lieven Keersmaekers
fonte
1
@ Dan: Certifique-se de entender o que a regex está fazendo! Regexes são perigosos nas mãos de pessoas que quase os conhecem. (Daí a citação que eu publiquei.)
Michael Myers
@ Dan, como está, o regex espera um espaço na frente e depois de cada *. Isso pode ser resolvido no regex, mas vamos deixar isso como um exercício.
Lieven Keersmaekers #
@Dan. Mudei o regex um pouco depois de criar os comentários. O original era: (:? \ D +) * x \ ^ (:? \ D) O novo é: (:? \ D +) * x \ ^ (:? \ D +)
Lieven Keersmaekers #
10
"5 * x^3 - 6 * x^1 + 1".replaceAll("\\W*\\*\\W*","").replaceAll("\\^(\\d+)","<sup>$1</sup>");

observe que unir as duas substituições em uma única regex / substituição seria uma péssima escolha, pois expressões mais gerais, como x^3 - 6 * xfalhariam.

vit123
fonte
3

Se isso for para qualquer expressão matemática geral e expressões entre parênteses forem permitidas, será muito difícil (talvez impossível) fazer isso com expressões regulares.

Se as únicas substituições são as que você mostrou, não é tão difícil de fazer. Primeiro *tire as roupas e depois use como Can Berk Güder mostrou para lidar com as roupas ^.

Michael Myers
fonte
Sim, expliquei posteriormente em uma nota do PS que estou usando isso para analisar uma representação básica de cadeia de um polinômio em algo mais legível por humanos. Obrigado!
22909 Dan Burzo
Todos os polinômios podem ser expandidos para um formulário que não envolve expressões entre parênteses. A correspondência de parênteses é muito divertida; portanto, você não deve se limitar apenas à forma expandida.
23811 Adam Jaskiewicz
3

Qual é o seu polinômio? Se você está "processando", estou imaginando algum tipo de árvore de sub-expressão sendo gerada em algum momento e pensaria que seria muito mais simples usar isso para gerar sua string do que analisar novamente a matéria-prima expressão com um regex.

Apenas lançando uma maneira diferente de pensar lá fora. Não tenho certeza do que mais está acontecendo no seu aplicativo.

Adam Jaskiewicz
fonte
Entendo o que você está dizendo ... isso realmente me pouparia muito sofrimento, mas estou tentando manter as coisas separadas. Queria que o Polynomial fosse uma classe autônoma que possa ser usada em outro contexto, como o console ... mas minha abordagem pode estar errada. O que você acha?
22909 Dan Burzo
Eu vejo o que você quer dizer. Incorporar as tags html no Polynomial.toString () definitivamente está quebrando o MVC. Acho que ainda faria algo assim, porque realmente tornaria as coisas mais fáceis. Talvez toHtmlString () ou algo assim ...
Adam Jaskiewicz
Ou talvez uma classe separada que o View use especificamente para formatar o polinômio? Então a própria classe Polynomial não precisa saber nada sobre a formatação.
Herms
Eu criei um novo método: toHTML (); quando você pensa sobre isso, toString () e toHTML () são basicamente a mesma coisa conceitualmente, exceto que empregam regras diferentes para formatação;
22909 Dan Burzo
Sim, eu realmente não gosto que a formatação específica da visualização esteja no objeto, mas permitiria que você usasse o polimorfismo para lidar com grande parte da lógica, em vez de uma declaração de switch gigante em um método de utilidade estática. Quando se trata baixo direito a ela, toString () também é vista específico formatação ...
Adam Jaskiewicz
1

Tente o seguinte:

String str = "5 * x^3 - 6 * x^1 + 1";
String replacedStr = str.replaceAll("\\^(\\d+)", "<sup>\$1</sup>");

Certifique-se de importar o java.util.regex.

cdmckay
fonte
Obrigado pela dica 'importar'. Infelizmente, o Eclipse me deu um erro para o segundo parâmetro: "Sequência de escape inválida" #
2200 Dan Burzo
Hmmm ... Eu testo no GroovyConsole, mas não no Java. Você também precisa se certificar de que tudo isso esteja em Java clichê (por exemplo, faça uma classe e jogue-a no método principal).
Cdmckay 10/03/09
A cadeia de substituição deve ser "<sup> $ 1 </sup>" - sem barras invertidas. O Groovy possui regras diferentes sobre barras invertidas; você deve testar seu código em Java.
Alan Moore
1
class Replacement 
{
    public static void main(String args[])
    {
        String Main = "5 * x^3 - 6 * x^1 + 1";
        String replaced = Main.replaceAll("(?m)(:?\\d+) \\* x\\^(:?\\d+)", "$1x<sup>$2</sup>");
        System.out.println(replaced);
    }
}
BigGinDaHouse
fonte
0

Você deseja analisar a captura em regex para manipular a quebra de 3 em ^ 3.

Ryan Graham
fonte
0

Tente isso, pode não ser o melhor caminho. mas funciona

String str = "5 * x^3 - 6 * x^1 + 1";
str = str.replaceAll("(?x)(\\d+)(\\s+?\\*?\\s+?)(\\w+?)(\\^+?)(\\d+?)", "$1$3<sup>$5</sup>");
System.out.println(str);
user5915163
fonte
7
A pergunta era de 2009 e já tem 8 respostas. A primeira resposta tem 82 votos. Sua resposta literalmente diz 'pode não ser o melhor caminho', indicando que existem soluções melhores, que já existem neste segmento.
Eric G
Não vejo resposta 'melhor' acima dela ... Mas há uma que, em alguns casos, é melhor abaixo.
Sergeych
0

Dê uma olhada no antlr4. Isso o levará muito mais longe na criação de uma estrutura em árvore do que apenas expressões regulares.

https://github.com/antlr/grammars-v4/tree/master/calculator (calculator.g4 contém a gramática necessária)

Em poucas palavras, você define a gramática para analisar uma expressão, usa o antlr para gerar código java e adiciona retornos de chamada para lidar com a avaliação quando a árvore está sendo construída.

Geoffrey Ritchey
fonte