Java; String ersetzen (mit regulären Ausdrücken)?

128

Im Rahmen eines Schulprojekts muss ich eine Zeichenfolge aus dem Formular ersetzen:

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

zu so etwas wie:

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

Ich glaube, dass dies mit regulären Ausdrücken möglich ist, aber ich weiß noch nicht, wie ich es machen soll.

Kannst du mir helfen?

PS Die eigentliche Aufgabe besteht darin, eine Java-Anwendung für die Polynomverarbeitung zu implementieren. Ich verwende diese Aufgabe, um polynomial.toString () vom Modell an die Ansicht zu übergeben, und ich möchte sie auf hübsche Weise mithilfe von HTML-Tags anzeigen.

Dan Burzo
quelle
2
Entschuldigung, können Sie genauer sein? Ich verstehe nicht, was du meinst.
Dan Burzo
5
Alter Witz. Codinghorror.com/blog/archives/001016.html enthält eine Erklärung.
Michael Myers
1
Oh :) Ich glaube, ich habe diesen Artikel vor einiger Zeit tatsächlich gelesen ... Sie schlagen also vor, dass Regex in meinem Fall nicht der richtige Weg ist?
Dan Burzo
Sie erlauben also nur Polynome in erweiterter Form?
Adam Jaskiewicz

Antworten:

175
str.replaceAll("\\^([0-9]+)", "<sup>$1</sup>");
Kann Berk Güder
quelle
ah ... aber du hast es verpasst, die "5 * x" auf "5x"
James Curran
Paarprobleme: \ ^ muss \\ ^ sein und $ muss \ $ sein.
CDMckay
Immer noch Fehler "ungültige Escape-Sequenz" ... fehlt mir etwas?
Dan Burzo
Dies gibt mir einen Fehler beim zweiten Parameter: str.replaceAll ("\\ ^ ([0-9] +)", "<sup> \ $ 1 </ sup>"); Ich verstehe es nicht ... :(
Dan Burzo
2
Ist es möglich, ein vorkompiliertes Muster zu verwenden? Dies kann nützlich sein, wenn Sie All alle mehrmals durch denselben regulären Ausdruck ersetzen.
Qed
38
private String removeScript(String content) {
    Pattern p = Pattern.compile("<script[^>]*>(.*?)</script>",
            Pattern.DOTALL | Pattern.CASE_INSENSITIVE);
    return p.matcher(content).replaceAll("");
}
Florian
quelle
8
Dies ist die beste IMO, da sie einen kompilierten Regex verwendet, das Pattern-Objekt jedoch ein statisches Objekt sein sollte.
Marcel Valdez Orozco
Lustige Sache ist, dass die replaceAllMethode implizit tut Pattern.compile(regex).matcher(testString).replaceAll(regexReplacementString)! Wenn Sie das Muster auf diese Weise wiederverwenden, werden redundante Objekte vermieden. Wie @MarcelValdezOrozco sagt, verhindert das statische Festlegen unnötige Aufrufe der Musterkompilierung. :)
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
quelle
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
quelle
1
@ Dan: Stellen Sie sicher, dass Sie verstehen, was die Regex tut! Regexes sind in den Händen von Menschen, die sie fast kennen, gefährlich . (Daher das Zitat, das ich gepostet habe.)
Michael Myers
@Dan, so wie es aussieht, erwartet der Regex ein Leerzeichen vor und nach jedem *. Dies kann in der Regex gelöst werden, aber lassen wir das als Übung.
Lieven Keersmaekers
@Dan. Ich habe den regulären Ausdruck etwas geändert, nachdem ich die Kommentare erstellt habe. Original war: (:? \ D +) * x \ ^ (:? \ D) Neu ist: (:? \ D +) * x \ ^ (:? \ D +)
Lieven Keersmaekers
10
"5 * x^3 - 6 * x^1 + 1".replaceAll("\\W*\\*\\W*","").replaceAll("\\^(\\d+)","<sup>$1</sup>");

Bitte beachten Sie, dass das Zusammenfügen beider Ersetzungen zu einem einzigen regulären Ausdruck / Ersatz eine schlechte Wahl wäre, da allgemeinere Ausdrücke wie z. B. x^3 - 6 * xfehlschlagen würden.

vit123
quelle
3

Wenn dies für einen allgemeinen mathematischen Ausdruck gilt und Klammerausdrücke zulässig sind, ist es sehr schwierig (möglicherweise unmöglich), dies mit regulären Ausdrücken zu tun.

Wenn die einzigen Ersetzungen die sind, die Sie gezeigt haben, ist es nicht so schwer zu tun. Zuerst Strip-Outs *, dann Capturing verwenden, wie Can Berk Güder gezeigt hat, um mit den Ss umzugehen ^.

Michael myers
quelle
Ja, ich habe später in einer PS-Notiz erklärt, dass ich dies verwende, um eine grundlegende Zeichenfolgendarstellung eines Polynoms in etwas menschlicher lesbares zu analysieren. Vielen Dank!
Dan Burzo
Polynome können alle zu einer Form erweitert werden, die keine Klammerausdrücke enthält. Paren-Matching macht jedoch großen Spaß, daher sollten Sie sich nicht nur auf die erweiterte Form beschränken.
Adam Jaskiewicz
3

Was ist dein Polynom? Wenn Sie es "verarbeiten", stelle ich mir vor, dass irgendwann eine Art Baum von Unterausdrücken generiert wird, und würde denken, dass es viel einfacher wäre, dies zum Generieren Ihrer Zeichenfolge zu verwenden, als das Raw erneut zu analysieren Ausdruck mit einem regulären Ausdruck.

Wirf einfach eine andere Denkweise da draußen. Ich bin mir nicht sicher, was sonst noch in Ihrer App los ist.

Adam Jaskiewicz
quelle
Ich verstehe, was du sagst ... das würde mir zwar viel Leid ersparen, aber ich versuche, die Dinge getrennt zu halten. Ich wollte, dass Polynom eine eigenständige Klasse ist, die in anderen Kontexten wie der Konsole verwendet werden kann ... aber mein Ansatz könnte falsch sein. Was denken Sie?
Dan Burzo
Ich verstehe was du meinst. Das Einbinden der HTML-Tags in Polynomial.toString () bricht MVC definitiv. Ich denke, ich würde trotzdem so etwas tun, weil es die Dinge wirklich einfacher machen würde. Vielleicht toHtmlString () oder so ...
Adam Jaskiewicz
Oder vielleicht eine separate Klasse, die die Ansicht speziell zum Formatieren des Polynoms verwendet? Dann muss die Polynomialklasse selbst nichts über die Formatierung wissen.
Herms
Ich habe eine neue Methode gemacht: toHTML (); Wenn Sie darüber nachdenken, sind toString () und toHTML () konzeptionell im Grunde dasselbe, außer dass sie unterschiedliche Regeln für die Formatierung verwenden.
Dan Burzo
Ja, ich mag es nicht wirklich, dass sich die ansichtsspezifische Formatierung im Objekt befindet, aber es würde Ihnen ermöglichen, Polymorphismus zu verwenden, um einen Großteil der Logik zu verarbeiten, anstatt eine riesige switch-Anweisung in einer statischen Dienstprogrammmethode. Wenn es darauf ankommt, ist toString () auch eine ansichtsspezifische Formatierung ...
Adam Jaskiewicz
1

Versuche dies:

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

Stellen Sie sicher, dass Sie java.util.regex importieren.

cdmckay
quelle
Vielen Dank für den 'Import'-Tipp. Leider gibt mir Eclipse einen Fehler für den zweiten Parameter: "Ungültige Escape-Sequenz"
Dan Burzo
Hmmm ... Ich teste es in GroovyConsole, aber nicht in Java. Sie müssen auch sicherstellen, dass dies alles in Java Boilerplate ist (dh eine Klasse erstellen und in eine Hauptmethode werfen).
CDMckay
Die Ersatzzeichenfolge sollte "<sup> $ 1 </ sup>" sein - keine Backslashes. Groovy hat unterschiedliche Regeln für Backslashes. Sie sollten Ihren Code in Java testen.
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
quelle
0

Sie sollten sich mit der Erfassung in Regex befassen, um das Umbrechen der 3 in ^ 3 zu handhaben.

Ryan Graham
quelle
0

Versuchen Sie dies, möglicherweise nicht der beste Weg. Aber es funktioniert

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
quelle
7
Die Frage stammt aus dem Jahr 2009 und hat bereits 8 Antworten. Die erste Antwort hat 82 Stimmen. Ihre Antwort lautet wörtlich "möglicherweise nicht der beste Weg", was darauf hinweist, dass es bereits in diesem Thread bessere Lösungen gibt.
Eric G
Ich sehe keine 'bessere' Antwort darüber ... Es gibt jedoch eine, die in einigen Fällen unten besser ist.
Sergeych
0

Schauen Sie sich antlr4 an. Sie werden beim Erstellen einer Baumstruktur viel weiter kommen als bei regulären Ausdrücken allein.

https://github.com/antlr/grammars-v4/tree/master/calculator (calculator.g4 enthält die Grammatik, die Sie benötigen)

Kurz gesagt, Sie definieren die Grammatik, um einen Ausdruck zu analysieren, verwenden antlr, um Java-Code zu generieren, und fügen Rückrufe hinzu, um die Auswertung beim Erstellen des Baums durchzuführen.

Geoffrey Ritchey
quelle