Zamiana znaków "obustronna"

0

Witam,
Piszę dziś z następującym problemem. Mam ciąg znaków. I chcę zamienić w nim wszystkie "a" na "o" i wszystkie "o" na "a" .Nie mogę tego zrobić za pomocą replace() jedno po drugim bo z czegoś takiego: aqok wyjdzie mi aqak, podczas gdy ma wyjść oqak. Nie chcę też sprawdzać litery po literze bo to mogą być naprawdę długie ciągi. Ma więc ktoś może pomysł jak to zrobić?

0

zamień a na jakis inny specyficzny ciąg np ##$## i następnie o na a i ##$## na o.

0
package test;


public class Test {

    public static void main(String[] args) {
        System.out.println(replace("aqok"));
    }

    private static String replace(String s) {
        StringBuilder sb = new StringBuilder(s);
        for (int i = 0; i < sb.length(); ++i) {
            char c = sb.charAt(i);
            if (c == 'a') {
                sb.setCharAt(i, 'o');
            } else if (c == 'o') {
                sb.setCharAt(i, 'a');
            }
        }
        return sb.toString();
    }
}

To jest najlatwiesze i najszybsze, szczegolnie jesli ciagi sa dlugie. Minus taki ze jesli dojdzie kolejna literka, i kolejna, i kolejna, to trzeba dodawac ify. Ale w pytaniu nie ma nic o tym.

Flappy napisał(a)

Nie chcę też sprawdzać litery po literze bo to mogą być naprawdę długie ciągi.

String.replaceAll() dziala na regexaxh, to raz, a dwa - naprawde myslisz ze mozna zamienic wszystkie wystapienia danej litery nie sprawdzajac calego ciagu? Do tego, w rozwiazaniu powyzej "naprawde dlugie ciagi" beda regexami jechane (cale) 3-krotnie.

Pozdro.

0
:: napisał(a)

Minus taki ze jesli dojdzie kolejna literka, i kolejna, i kolejna, to trzeba dodawac ify.

Dodam tylko nieśmiało, że tworzenie "ifów" dla porównywania wartości skalarnych jakimi są liczby całkowite, litery itd. ze stałymi (literałami) to raczej średni pomysł. Od takich rzeczy jest znacznie bardziej czytelna (i szybsza) instrukcja switch. "Ifów" trzeba używać tylko gdy porównuje się ze sobą dwie zmienne lub obiekty poprzez metodę equals().

0

Ty napisales ze switch jest lepszy, w innym watku w innym dziale ktos napisal ze switch jest bardzo niebezpiecznym elementem jezyka. Kwestia gustu, zysk na szybkosci jest raczej bardzo niewielki.

Z ciekawosci, sprawdzilem jak to wyglada po kompilacji. Taki kod:

class Test {
    int tested = 17;

    void f_if() {
        if (tested == 1) {
        } else if (tested == 2) {
        } else {
        }
    }

    void f_switch() {
        switch (tested) {
        case 1:
            break;
        case 2:
            break;
        default:
        }
    }

}

po kompilacji bez zadnych dodatkowych przelacznikow, i potraktowaniu javap -c (wycialem niepotrzebne elementy):

void f_if();
  Code:
   0:   aload_0
   1:   getfield        #2; //Field tested:I
   4:   iconst_1
   5:   if_icmpne       11
   8:   goto    19
   11:  aload_0
   12:  getfield        #2; //Field tested:I
   15:  iconst_2
   16:  if_icmpne       19
   19:  return

void f_switch();
  Code:
   0:   aload_0
   1:   getfield        #2; //Field tested:I
   4:   lookupswitch{ //2
                1: 32;
                2: 35;
                default: 38 }
   32:  goto    38
   35:  goto    38
   38:  return

Wyglada na to ze faktycznie jest mniej operacji. Opcode lookupswitch jednak sam w sobie jest zaimplementowany za pomoca porownan, wiec jedyny zysk jest taki ze opcode getfield jest ladowany raz (jest jeszcze opcode tableswitch ktory czasami moze byc wykorzystany i spec mowi ze mozebyc szybszy). Prawdopodobnie jest ta wartosc w jakims rejestrze (nie jest volatile) wiec pobranie to blysk.
Czy switch jest znacznie szybszy klocilbym sie ;d Co do czytelnosci, kolejny spor bez konca.

Ale dzieki za informacje, do tej pory myslalem ze taki switch i ify kompiluje sie do tego samego.
Pozdro.


0

Hmm, mam nadzieję, że wybaczony zostanie mi ten offtop. :)

:: napisał(a)

Ty napisales ze switch jest lepszy, w innym watku w innym dziale ktos napisal ze switch jest bardzo niebezpiecznym elementem jezyka.

Być może ktoś bez zastanowienia trzymał się "pogardzania" etykietami (podobnie jak instrukcją goto). Switch ma moim zdaniem tylko dwa, ale za to dwa najlepsze zastosowania. Pierwsze, to operacje na zbiorach gdzie kilku wybranym elementom przypisuje się (nieregularnie) jedną akcję lub daną - a drugie, to tzw. "falltrough" (kaskada), czyli konstrukcja bardzo polepszająca czytelność i eliminująca nadmiarowość kodu w krytycznych sekcjach programu.
Wystąpienie kaskady jest przez javę ostrzegane - głównie dlatego, że jest to wyrafinowany sposób użycia switch, umiejętnie stosowany przez nielicznych. A o break często zapominają Ci, którzy raczej nie potrafią się switchem posługiwać, choć używają go często.
Powiedziałbym nawet, że jeżeli każda sekcja switch posiada break i każdej sekcji odpowiada wyłącznie jedna etykieta/wartość, to bardziej sensowne i eleganckie jest użycie tablicy sterującej wyborem właściwego kodu. Tak zresztą implementowane są metody polimorficzne.

:: napisał(a)

Kwestia gustu, zysk na szybkosci jest raczej bardzo niewielki.

Obecnie gdy kod javy jest w całości przed użyciem kompilowany do instrukcji maszynowych, co oznacza, że można w javie oczekiwać wydajności zbliżonej do C++ - ma to pewne znaczenie. Oczywiście nie dla osób, którym wszystko jedno czy wystąpi jedna, pięć czy 200 niepotrzebnych instrukcji.

:: napisał(a)

Co do czytelnosci, kolejny spor bez konca.

Pewnie tak. Podam jednak konkretny i bardzo elegancki przykład jak bardzo switch poprawia czytelność i sterowanie:

	//...
	do switch(bufor.getImage().validate(getGraphicsConfiguration()))
	{	//uwaga, instrukcje bez break
		case VolatileImage.IMAGE_INCOMPATIBLE:
			testRozmiaru(bufor.getSize());
			bufor.wymianaEkranu();
		case VolatileImage.IMAGE_RESTORED:
			renderowanie();
		case VolatileImage.IMAGE_OK:
			odrysowanieBufora();
	}
	while(bufor.getImage().contentsLost());
	//...

Jest tu zaledwie jedna kaskada trzystopniowa. Gdybyś chciał napisać tak samo funkcjonujący kawałek kodu za pomocą ifów itp. to kod byłby trzy razy dłuższy, dużo mniej czytelny, zawierający powtórzenia i mniej efektywny. Zauważ, że nie ma tu ani jednego break, a w postaci skompilowanej ma efektywność kodu napisanego natywnie w assemblerze (szczególnie to widać po kompilacji javy wprost do kodu maszynowego).
A przecież w kodzie sterującym urządzeniami (lub każdym innym uwzględniającym realny świat) zdarzają się w jednym switchu dwie kaskady nawet pięciostopniowe.
Bywa, że widzę czasem kompletnie nieczytelny kod mający 200-300 wierszy, który po użyciu switcha skraca się dziesięciokrotnie. A czytelność staje się tak idealna, że od pierwszego rzutu okiem wynajduje się błędy, których prawdopodobieństwo wykrycia czytając kod jest znikome.

:: napisał(a)

do tej pory myslalem ze taki switch i ify kompiluje sie do tego samego.

Z założenia konstrukcji nie może się tak kompilować. Switch nie jest cukierkiem składniowym bo ma możliwości (bez użycia dodatkowych zmiennych) niedostępne dla żadnej innej konstrukcji.
Pozdrawiam.

1 użytkowników online, w tym zalogowanych: 0, gości: 1