Wypisanie tekstu z nr wiersza

0

Witam, mam problem, z którym męczę się kilka dni i chyba już samemu nie znajdę rozwiązania. Mam metodę searchWord, której parametrem jest wejściowy String i szukane słowo. Metoda ma za zadanie ponumerować i szukać tylko te zdania , która posiadają szukane słowo. Oczywiście każde zdanie w Stringu ma się kończyć przejściem do nowej linii. Moje dwa problemy to: brak możliwości wypisania stringa w pętli, bo ostatnie zdanie zawsze nie będzie miało przejścia do nowej linii, dlatego wypisując go poza pętlą wypisze się również to zdanie, które szukanego słowa nie posiada oraz chyba coś namieszałem w kodzie bo nie zawsze wyświetla mi się z odpowiednimi spacjami i zjada ostatnią literę. Poniżej kod:

public class TextWordFinder {

   TextWordFinder searchWord(String text, String searchWord) {
      int row = 0;
      int firstIndex = 0;
      int temp = 0;
      for (int i = 0; i < text.length(); i++) {

         if (text.charAt(i) == '\n') {
            row++;
            if(text.substring(firstIndex,i).contains(searchWord)) {
               System.out.println(row +text.substring(firstIndex,i));
            }
            firstIndex = i;
         }
         temp = i;
      }
      System.out.print(text.substring(firstIndex,temp));
         return new TextWordFinder();
   }
}

0

Wywal ten temp, bo to bez sensu. Po prostu zadeklaruj zmienną i przed pętlą. To powinno rozwiązać jeden z Twoich problemów.

0

Trochę nie rozumiem, zrobiłem według Twoich zaleceń i jest podobnie.

1

o_O Zacznij od text.split("\n") bo teraz to robisz jakiś zupełnie niepotrzebny hardkor.

0

Dobra chyba zrozumiałem aluzję, oto poprawiony kod:

public class TextWordFinder {

   TextWordFinder searchWord(String text, String searchWord) {
      String strArray[] = text.split("\n");
      int row = 0;
      int i = 0;
      for ( i = 0; i < strArray.length; i++) {

         if (strArray[i].contains(searchWord)) {
            row++;
            System.out.println(row +"." +strArray[i]);
         }
      }

         return new TextWordFinder();
   }
}
0

A po co ci ta zmienna row skoro zmienna i już określa ci numer zdania? Zresztą teraz to raczej źle działa bo robisz row++ tylko dla znalezionego więc będzie ci wypisywać 1,2,3... zawsze. No i nie bardzo rozumiem ten return tutaj.

0

Moje przeoczenie, rzeczywiście row jest niepotrzebne, bo zmienna i już określa nr wiersza, nie rozumiem dlaczego by źle działała zmienna row, skoro właśnie chciałem dla znalezionego wypisać konkretne zdania. Co do return to generalnie chciałem, żeby metoda zwracała i nr linijki i zdanie, jako że w metodzie dwóch returnów nie mogę dać, to ktoś mi podpowiedział, że jeśli nie mogę zwrócić dwóch rzeczy z metody, to powinienem zwrócić obiekt, który przechowa dwie wartości.

0
  1. No ale row++ robiłeś tylko dla znalezionych zdań więc zawsze wypisywałbyś kolejne numerki i nie miałyby nic wspólnego z numerami zdań!
  2. No można tak zrobić, potwierdzam, ale twój obiekt wcale takich informacji nie posiada xD Robisz return new TextWordFinder(); gdzie tu jakaś informacja o numerze zdania czy o zdaniu? Zresztą to i tak nie ma sensu, bo co jak zdań jest więcej niż 1? Jeśli w ogóle to musiałbyś mieć jakieś List<Result> gdzie Result to klasa która przechowuje int i String.
0

@charms:

Przeklej treść zadania/polecenia. BTW, z góry przepraszam, ale wydaje mi się, że jak na razie to nie rozróżniasz klasy od metody.

0

Napisać funkcję:
public static void szukaj(String nazwaPlikWe, String nazwaPlikWy,
String slowo)
której zadaniem jest znalezienie wszystkich wierszy w pliku, które zawierają szukane słowo. Wszystkie wiersze, które zawierają słowo powinny zostać zapisane w
pliku wynikowym wraz z nr wiersza (z pierwszego pliku). Nazwa pierwszego pliku
zapamiętana jest w parametrze nazwaPlikWe, nazwa pliku wynikowego podana
jest w parametrze nazwaPlikWy, natomiast szukane słowo w parametrze slowo.
Przykład - plik wejściowy:
Ala ma jutro egzamin z biologii.
Jan myje auto.
Eh, jutro kolejny egzamin.
Nie lubie polityki.
Jeżeli szukanym słowem byłoby ”egzamin”, to plik wynikowy powinien wyglądać
następująco:
1: Ala ma jutro egzamin z biologii.
3: Eh, jutro kolejny egzamin.

Ja postanowiłem zrobić to trochę inaczej i podzielić to na kilka klas, jedna klasa zapisuje i odczytuje danego Stringa, druga klasa szuka danego słowa i zapisuje zdania ze znalezionym słowem do PlikWy

Czyli mogę zwrócić tablicę stringów albo listę.

0

@charms:

charms napisał(a):

Czyli mogę zwrócić tablicę stringów albo listę.

No widzisz i to jest teraz jakiś konkret. Poprzednio jak napisałeś, że ma ponumerować, to niewiele z tego wynikało.
To, że rozbijasz na klasy nie szkodzi - musisz tylko pamiętać o jakimś flow gdzie i w którym miejscu jakie obiekty tworzysz, albo skorzystać z metod static (nie musisz wtedy tworzyć instancji). To które operacje w jakiej klasie się znajdą, jest kwestią umowną i mogą być różne rozwiązania skutecznie tworzące plik wynikowy - możesz zarówno w jednej klasie mieć wszystkie metody, jak i każdą metodę w osobnej klasie. Na tym etapie nauki chyba nie ma to znaczenia, aczkolwiek może gorzej, lub lepiej ze względu na clean code wyglądać.

Ja postanowiłem zrobić to trochę inaczej i podzielić to na kilka klas, jedna klasa zapisuje i odczytuje danego Stringa, druga klasa szuka danego słowa i zapisuje zdania ze znalezionym słowem do PlikWy

Nie bardzo rozumiem dlaczego pierwsza klasa ma zapisywać danego Stringa - to jest całkowicie bez sensu. Ty masz przeczytać dane a zapisać wynik. Czyli jak chcesz "rozbić odpowiedzialności" to miałbyś 3 etapy (np. po jednej metodzie do każdego):

  1. Wczytanie pliku do listy stringów (jeden wiersz = jeden element)
  2. Filtrowanie danych (+ numeracja) po zdanym kryterium (= zawieranie słowa)
  3. Zapisanie do pliku np. nowej listy stringów

Aczkolwiek nie wiem, czy to nie przeinżynierowanie będzie, to się w kilku linijkach da zrobić, może nawet krócej:

    public static void szukaj(String nazwaPlikWe, String nazwaPlikWy, String slowo) {
        try (Scanner sc = new Scanner(new File(nazwaPlikWe)); FileWriter fw = new FileWriter(nazwaPlikWy)){
            int i = 1;
            while (sc.hasNextLine()) {
                String current = sc.nextLine();
                if (current.contains(slowo)) fw.append(i + ". " + current + "\n");
                i++;
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
0

Ok, dziękuje za rzetelną odpowiedź. Po prostu kolega mi doradził, abym nauczył się rozdzielać poszczególne odpowiedzialność na różne metody/klasy. Co więcej chodziło o to że zapisuje stringa do pliku PlikWe by potem odczytać tego Stringa i zapisać docelowego w nowym pliku PlikWy.

1
    public static void find(String inputFile, String outputFile, String word) throws IOException {
        AtomicInteger rows = new AtomicInteger(0);
        List<String> matched = Files.lines(Paths.get(inputFile))
                .filter(line -> line.contains(word))
                .map(line -> rows.incrementAndGet() + " " + line)
                .collect(Collectors.toList());
        Files.write(Paths.get(outputFile), matched);
    }

Albo xakep-style bez collecta w ogóle:

        AtomicInteger rows = new AtomicInteger(0);
        Stream<CharSequence> matched = Files.lines(Paths.get(inputFile))
                .filter(line -> line.contains(word))
                .map(line -> rows.incrementAndGet() + " " + line);
        Files.write(Paths.get(outputFile), matched::iterator);
0
Shalom napisał(a):
>     public static void find(String inputFile, String outputFile, String word) throws IOException {
>         AtomicInteger rows = new AtomicInteger(0);
>         List<String> matched = Files.lines(Paths.get(inputFile))
>                 .filter(line -> line.contains(word))
>                 .map(line -> rows.incrementAndGet() + " " + line)
>                 .collect(Collectors.toList());
>         Files.write(Paths.get(outputFile), matched);
>     }
> ```
> Albo xakep-style bez collecta w ogóle:
> ```java
>         AtomicInteger rows = new AtomicInteger(0);
>         Stream<CharSequence> matched = Files.lines(Paths.get(inputFile))
>                 .filter(line -> line.contains(word))
>                 .map(line -> rows.incrementAndGet() + " " + line);
>         Files.write(Paths.get(outputFile), matched::iterator);
> ```


Wszystko pięknie, ładnie, nowocześnie, tylko nie odpowiada temu co OP chciał uzyskać, tj. w pliku wynikowym zapisać tylko wiersze spełniające warunek zawierania słowa, wraz z ich numerem w oryginalnym pliku (ostatni post OP na poprzedniej stronie). 

while vs streams 
1 : 0

No, chyba, że np:

```java
            Files.write(Paths.get(outputFile), Files.lines(Paths.get(inputFile))
                    .map(line -> rows.incrementAndGet() + ". " + line)
                    .filter(line -> line.contains(word)).collect(Collectors.toList()));

:D

P.S.
Nie to, żebym nie doceniał. Dziękuję!

0

Nawet nie wiem co się zadziało powyżej u Was w kodzie, ale to chyba dlatego że lambdy są dla mnie nieznane. Skoro Scannery i while już nie powinien być używany, to FileWriter i PrintWriter również?:D

0
charms napisał(a):

Nawet nie wiem co się zadziało powyżej u Was w kodzie, ale to chyba dlatego że lambdy są dla mnie nieznane. Skoro Scannery i while już nie powinien być używany, to FileWriter i PrintWriter również?:D

Musisz czytać ten kod po hebrajsku - od prawej do lewej.

- Jesteś Java8 developerem?
- Tak.
- To powiedz coś po javo8wemu!
- "Listę będącą kolekcją, po słowie zawieranym przefiltrowanych linii ponumerownych (i) odczytanych 
  z pliku *inputFile* do pliku *outputFile* (weź i) zapisz. (Młody Padawanie)*"

*) od tłumacza z javovego na Yoda Language
0

Chyba muszę uczyć się programowania podczas oglądania Star Warsów :D

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