Giava; Sostituzione di stringhe (utilizzando espressioni regolari)?


129

Come parte di un progetto per la scuola, devo sostituire una stringa dal modulo:

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

a qualcosa come:

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

Credo che questo possa essere fatto con le espressioni regolari, ma non so ancora come farlo.

Puoi darmi una mano?

PS Il compito effettivo è quello di implementare un'applicazione Java di elaborazione polinomiale, e la sto usando per passare polynomial.toString () dal modello alla vista, e voglio visualizzarlo usando i tag html in un modo carino.


2
Mi scusi, puoi essere più specifico? Non capisco cosa intendi.
Dan Burzo

5
Vecchia barzelletta. codinghorror.com/blog/archives/001016.html ha una spiegazione.
Michael Myers

1
Oh :) Penso di aver letto quell'articolo qualche tempo fa ... Quindi stai suggerendo che regex non è la strada da percorrere nel mio caso?
Dan Burzo

Quindi permetti solo i polinomi in forma espansa?
Adam Jaskiewicz

Risposte:


176
str.replaceAll("\\^([0-9]+)", "<sup>$1</sup>");

ah ... ma ti sei perso il collasso da "5 * x" a "5x"
James Curran

Problemi di coppia: \ ^ deve essere \\ ^ e $ deve essere \ $.
cdmckay

Ricevo ancora l'errore "sequenza di escape non valida" ... mi manca qualcosa?
Dan Burzo

questo mi dà un errore al secondo parametro: str.replaceAll ("\\ ^ ([0-9] +)", "<sup> \ $ 1 </sup>"); Non capisco ... :(
Dan Burzo

2
È possibile utilizzare un pattern precompilato? Questo potrebbe essere utile se sostituisci Tutto con la stessa regex molte volte.
qed

38
private String removeScript(String content) {
    Pattern p = Pattern.compile("<script[^>]*>(.*?)</script>",
            Pattern.DOTALL | Pattern.CASE_INSENSITIVE);
    return p.matcher(content).replaceAll("");
}

8
Questo è il miglior IMO, perché utilizza un Regex compilato, ma l'oggetto Pattern dovrebbe essere un oggetto statico.
Marcel Valdez Orozco

La cosa divertente è che il replaceAllmetodo lo fa implicitamente Pattern.compile(regex).matcher(testString).replaceAll(regexReplacementString)! Quindi, se riutilizzi il pattern in questo modo, gli oggetti ridondanti verranno evitati. Inoltre, come dice @MarcelValdezOrozco, renderlo statico eviterà invocazioni non necessarie alla compilazione di pattern. :)
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>");

11
"5 * x^3 - 6 * x^1 + 1".replaceAll("\\W*\\*\\W*","").replaceAll("\\^(\\d+)","<sup>$1</sup>");

tieni presente che unire entrambe le sostituzioni in una singola regex / sostituzione sarebbe una cattiva scelta perché espressioni più generali come x^3 - 6 * xfallirebbero.


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
}

1
@ Dan: assicurati di aver capito cosa sta facendo la regex! Le espressioni regolari sono pericolose nelle mani di persone che quasi le conoscono. (Da qui la citazione che ho pubblicato.)
Michael Myers

@ Dan, così com'è, la regex si aspetta uno spazio davanti e dopo ogni *. Questo può essere risolto nell'espressione regolare, ma lasciamolo come esercizio.
Lieven Keersmaekers

@ Dan. Ho cambiato un po 'la regex dopo aver creato i commenti. L'originale era: (:? \ D +) * x \ ^ (:? \ D) Il nuovo è: (:? \ D +) * x \ ^ (:? \ D +)
Lieven Keersmaekers

3

Se questo è per qualsiasi espressione matematica generale e le espressioni parentetiche sono consentite, sarà molto difficile (forse impossibile) farlo con le espressioni regolari.

Se le uniche sostituzioni sono quelle che hai mostrato, non è così difficile da fare. Prima rimuovi le *s, poi usa la cattura come ha mostrato Can Berk Güder per gestire le ^'s.


Sì, in seguito ho spiegato in una nota di PS che lo sto usando per analizzare una rappresentazione di stringa di base di un polinomio in qualcosa di più leggibile dall'uomo. Grazie!
Dan Burzo

I polinomi possono essere tutti espansi in una forma che non implica espressioni parentetiche. L'abbinamento tra genitori è molto divertente, quindi non dovresti limitarti alla sola forma espansa.
Adam Jaskiewicz

3

Qual è il tuo polinomio? Se lo stai "elaborando", immagino che a un certo punto venga generata una sorta di albero di sottoespressioni e penserei che sarebbe molto più semplice usarlo per generare la tua stringa piuttosto che analizzare nuovamente il grezzo espressione con una regex.

Sto solo lanciando un modo diverso di pensare là fuori. Non sono sicuro di cos'altro stia succedendo nella tua app.


Capisco cosa stai dicendo ... mi risparmierebbe davvero molta sofferenza, ma sto cercando di tenere le cose separate. Volevo che Polynomial fosse una classe autonoma che può essere utilizzata in altri contesti, come la console ... ma il mio approccio potrebbe essere sbagliato. Cosa ne pensi?
Dan Burzo

Capisco cosa vuoi dire. Incorporare i tag html in Polynomial.toString () sta decisamente infrangendo MVC. Penso che farei comunque qualcosa del genere, perché renderebbe davvero le cose più facili. Forse toHtmlString () o qualcosa del genere ...
Adam Jaskiewicz

O forse una classe separata che la vista usa specificamente per formattare il polinomio? Quindi la stessa classe Polynomial non ha bisogno di sapere nulla sulla formattazione.
Herms

ho creato un nuovo metodo: toHTML (); a pensarci bene, toString () e toHTML () sono sostanzialmente la stessa cosa concettualmente, tranne che impiegano regole differenti per la formattazione;
Dan Burzo

Sì, non mi piace molto che la vista-specifica formattazione in oggetto, ma sarebbe permetterà di utilizzare il polimorfismo a che fare con un sacco di logica piuttosto che un'istruzione switch gigante in un metodo di utilità statico. Alla fine, toString () è anche una formattazione specifica per la vista ...
Adam Jaskiewicz

1

Prova questo:

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

Assicurati di importare java.util.regex.


Grazie per il suggerimento di "importazione". Sfortunatamente, Eclipse mi dà un errore per il secondo parametro: "Sequenza di escape non valida"
Dan Burzo

Hmmm ... Lo provo in GroovyConsole ma non in Java. Devi anche assicurarti che questo sia tutto in Java boilerplate (cioè creare una classe e lanciarla in un metodo principale).
cdmckay

La stringa di sostituzione dovrebbe essere "<sup> $ 1 </sup>", senza barre rovesciate. Groovy ha regole diverse sui backslash; dovresti testare il tuo codice in 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);
    }
}

0

Dovrai esaminare la cattura in regex per gestire il wrapping del 3 in ^ 3.


0

Prova questo, potrebbe non essere il modo migliore. ma funziona

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);

7
La domanda era del 2009 e ha già 8 risposte. La prima risposta ha 82 voti. La tua risposta dice letteralmente "potrebbe non essere il modo migliore" indicando che ci sono soluzioni migliori, che ci sono, già in questo thread.
Eric G,

Non vedo alcuna risposta "migliore" sopra ... Ce n'è una che in alcuni casi è migliore sotto, però.
sergeych

0

Dai un'occhiata a antlr4. Ti porterà molto più avanti nella creazione di una struttura ad albero rispetto alle sole espressioni regolari.

https://github.com/antlr/grammars-v4/tree/master/calculator (calculator.g4 contiene la grammatica di cui hai bisogno)

In poche parole, si definisce la grammatica per analizzare un'espressione, si usa antlr per generare codice java e si aggiungono callback per gestire la valutazione quando l'albero viene costruito.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.