Jawa; Zastąpić ciąg (używając wyrażeń regularnych)?


129

W ramach projektu dla szkoły muszę zamienić ciąg znaków z formularza:

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

na coś takiego:

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

Uważam, że można to zrobić za pomocą wyrażeń regularnych, ale jeszcze nie wiem, jak to zrobić.

Czy możesz mi pomóc?

PS Rzeczywistym zadaniem jest zaimplementowanie aplikacji Java do przetwarzania wielomianowego i używam tego do przekazywania polynomial.toString () z modelu do widoku i chcę wyświetlić go za pomocą tagów HTML w ładny sposób.


2
Przepraszam, czy możesz być bardziej szczegółowy? Nie rozumiem, co masz na myśli.
Dan Burzo


1
Oh :) Myślę, że czytałem ten artykuł jakiś czas temu ... Sugerujesz więc, że regex nie jest właściwą drogą w moim przypadku?
Dan Burzo,

Więc zezwalasz tylko na wielomiany w postaci rozszerzonej?
Adam Jaskiewicz

Odpowiedzi:


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

ach ... ale przegapiłeś zwijanie „5 * x” do „5x”
James Curran,

Problemy z parą: \ ^ musi być \\ ^, a $ musi być \ $.
cdmckay

Nadal pojawia się błąd „nieprawidłowa sekwencja ucieczki” ... czy coś mi brakuje?
Dan Burzo

to daje mi błąd w drugim parametrze: str.replaceAll ("\\ ^ ([0-9] +)", "<sup> \ $ 1 </sup>"); Nie rozumiem ... :(
Dan Burzo

2
Czy można użyć wstępnie skompilowanego wzorca? Może to być przydatne, jeśli wielokrotnie zastępujesz wszystko tym samym wyrażeniem regularnym.
napisano

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

8
Jest to najlepsza IMO, ponieważ używa skompilowanego Regex, ale obiekt Pattern powinien być obiektem statycznym.
Marcel Valdez Orozco

Zabawne jest to, że replaceAllmetoda niejawnie działa Pattern.compile(regex).matcher(testString).replaceAll(regexReplacementString)! Jeśli więc ponownie użyjesz wzorca w ten sposób, unikniesz zbędnych obiektów. Ponadto, jak mówi @MarcelValdezOrozco, uczynienie go statycznym zapobiegnie niepotrzebnym wywołaniom kompilacji wzorców. :)
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>");

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: Upewnij się, że rozumiesz, co robi wyrażenie regularne! Regeksy są niebezpieczne w rękach ludzi, którzy prawie je znają. (Stąd cytat, który zamieściłem.)
Michael Myers

@Dan w obecnej postaci wyrażenie regularne oczekuje spacji przed i po każdym *. Można to rozwiązać w wyrażeniu regularnym, ale zostawmy to jako ćwiczenie.
Lieven Keersmaekers

@Dan. Po utworzeniu komentarzy zmieniłem nieco wyrażenie regularne. Oryginał: (:? \ D +) * x \ ^ (:? \ D) Nowy to: (:? \ D +) * x \ ^ (:? \ D +)
Lieven Keersmaekers

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

zwróć uwagę, że połączenie obu zamian w jednym wyrażeniu regularnym / zamianie byłoby złym wyborem, ponieważ bardziej ogólne wyrażenia, takie jak x^3 - 6 * xzawiodłyby.


3

Jeśli dotyczy to dowolnego ogólnego wyrażenia matematycznego, a wyrażenia w nawiasach są dozwolone, będzie to bardzo trudne (być może niemożliwe) przy użyciu wyrażeń regularnych.

Jeśli jedyne zamienniki to te, które pokazałeś, nie jest to trudne. Najpierw *pozbądź się, a potem użyj przechwytywania, jak pokazał Can Berk Güder, aby poradzić sobie z nimi ^.


Tak, później wyjaśniłem w notatce PS, że używam tego do parsowania podstawowej reprezentacji ciągu wielomianu w coś bardziej czytelnego dla człowieka. Dzięki!
Dan Burzo,

Wszystkie wielomiany można rozszerzyć do postaci bez wyrażeń w nawiasach. Dopasowywanie pasm to jednak świetna zabawa, więc nie powinieneś ograniczać się tylko do rozszerzonej formy.
Adam Jaskiewicz

3

Jaki jest twój wielomian? Jeśli ją „przetwarzasz”, wyobrażam sobie, że w pewnym momencie zostanie wygenerowane jakieś drzewo wyrażeń podrzędnych i myślę, że byłoby o wiele łatwiej użyć tego do wygenerowania ciągu niż ponownie przeanalizować surowe wyrażenie z wyrażeniem regularnym.

Po prostu rzucam inny sposób myślenia. Nie wiem, co jeszcze dzieje się w Twojej aplikacji.


Rozumiem, co mówisz ... to rzeczywiście oszczędziłoby mi wiele cierpienia, ale staram się to rozdzielić. Chciałem, aby Polynomial był samodzielną klasą, której można używać w innym kontekście, na przykład w konsoli ... ale moje podejście może być złe. Co myślisz?
Dan Burzo

Rozumiem, co masz na myśli. Włączenie tagów html do Polynomial.toString () zdecydowanie łamie MVC. Myślę jednak, że nadal bym coś takiego zrobił, bo to naprawdę ułatwiłoby sprawę. Może toHtmlString () czy coś ...
Adam Jaskiewicz

A może osobna klasa, której View używa specjalnie do formatowania wielomianu? Wtedy sama klasa Polynomial nie musi nic wiedzieć o formatowaniu.
Herms

stworzyłem nową metodę: toHTML (); kiedy się nad tym zastanowić, toString () i toHTML () są koncepcyjnie w zasadzie tym samym, z wyjątkiem tego, że stosują różne reguły formatowania;
Dan Burzo,

Tak, nie podoba mi się to, że formatowanie specyficzne dla widoku znajduje się w obiekcie, ale pozwoliłoby ci użyć polimorfizmu do radzenia sobie z dużą częścią logiki, a nie gigantyczną instrukcją przełącznika w statycznej metodzie narzędziowej. Jeśli chodzi o to, toString () jest również formatowaniem specyficznym dla widoku ...
Adam Jaskiewicz

1

Spróbuj tego:

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

Pamiętaj, aby zaimportować plik java.util.regex.


Dzięki za wskazówkę dotyczącą importu. Niestety Eclipse daje mi błąd dla drugiego parametru: "Nieprawidłowa sekwencja ucieczki"
Dan Burzo

Hmmm ... Testuję to w GroovyConsole, ale nie w Javie. Musisz także upewnić się, że to wszystko jest w szablonie Java (tj. Utwórz klasę i wrzuć ją do metody głównej).
cdmckay

Ciąg zastępujący powinien mieć postać „<sup> $ 1 </sup>” - bez odwrotnych ukośników. Groovy ma inne zasady dotyczące odwrotnych ukośników; powinieneś przetestować swój kod w Javie.
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

Będziesz chciał przyjrzeć się przechwytywaniu w wyrażeniu regularnym, aby obsłużyć zawijanie 3 w ^ 3.


0

Spróbuj tego, może nie jest to najlepszy sposób. ale to działa

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
Pytanie pochodziło z 2009 roku i ma już 8 odpowiedzi. Pierwsza odpowiedź ma 82 głosy. Twoja odpowiedź dosłownie mówi „może nie być najlepszym sposobem”, wskazując, że są lepsze rozwiązania, które są, już w tym wątku.
Eric G

Nie widzę „lepszej” odpowiedzi powyżej… Jest jednak taka, która w niektórych przypadkach jest lepsza poniżej.
sergeych

0

Spójrz na antlr4. Pozwoli ci to na dużo dalej w tworzeniu struktury drzewa niż same wyrażenia regularne.

https://github.com/antlr/grammars-v4/tree/master/calculator (kalkulator.g4 zawiera gramatykę, której potrzebujesz)

Krótko mówiąc, definiujesz gramatykę do analizowania wyrażenia, używasz antlr do generowania kodu java i dodajesz wywołania zwrotne do obsługi oceny podczas budowania drzewa.

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.