Standardklassen String TDA43 I Programmerade system Föreläsning (OH-bilder 8) Klassen String Mer om fält Något om inläsning Christer Carlsson Texter handhas i Java med standardklassen String. Ett objekt av klassen String består av en följd av tecken, dvs element av typen char. I Java används en internationell standard för att lagra tecken som kallas Unicode. De svenska tecknen ligger inte i följd i denna standard varför inte tecken och ord kan jämföras enligt alfabetisk ordning utan användning av en jämförare. En jämförare är ett objekt av klassen Collactor, som finns i paketet java.text.collator. En jämförare deklareras på följande sätt: Collator co = Collator.getInstance(); varvid de språkkonvensioner som är satta till default erhålls. Alternativt kan man vid skapadet av jämföraren ange vilka språkkonvensioner som skall användar: Collator co = Collator.getInstance(new Locale("sv", "SE")); Texter kan jämföras med metoderna compare eller equals: co.compare(s,s) co.equals(s, s) Det är möjligt att sätta "nivån" på jämföraren: co.setstrength(collator.primary) co.setstrength(collator.secondary) co.setstrength(collator.tertiary) ger värdet om s och s är alfabetiskt lika, ett värde < om s kommer för s och ett värde > s kommer för s. ger true om s och s är alfabetiskt lika, annars fås värdet false. Skiljer endast på olika bokstäver. Skiljer på små och stora bokstäver. Skiljer på små och stora bokstäver, samt på utsmyckade bokstäver. Metoder i standardklassen String Metoder i standardklassen String int length() char charat(int index) int compareto(string str) String concat(string str) ger antalet tecken i aktuell sträng ger tecket i position index gör alfabetisk jämför mellan aktuell sträng och str. Ger värdet om aktuell sträng och argumentet är alfabetiskt lika, ett värde mindre än om argumentet är större och ett värde större än om argumentet är mindre lägger till str efter aktuell sträng int indexof(string str) int lastindexof(string str) String replace (char oldchar, char newchar) ger första förekomsten av strängen str i den aktulla strägen, om str inte finns returneras - ger sista förekomsten av strängen str i den aktulla strägen, om str inte finns returneras - ger en kopia av aktuell sträng där alla förekomster av tecknet oldchar bytts mot tecknet newchar boolean equals(string str) ger true om str är lika med aktuell sträng, annars ges värdet false String substring(int index) ger den delsträng av aktuell sträng som börjar i position index boolean equalsignorecase(string str) int indexof(char c) int lastindexof(char c) int indexof(char c, int n) jämför aktuell sträng med strängen str utan hänsyn till versaler och germaner. Ger värdet true om str är lika med aktuell sträng, annars ges värdet false ger första förekomsten av tecknet c i den aktulla strägen, om c inte finns returneras - ger sista förekomsten av tecknet c i den aktulla strägen, om c inte finns returneras - ger positionen för första förekomsten av tecknet c från position n och framåt String substring(int startindex, int endindex) String tolowercase() String touppercase() String trim() static String valueof(int n)... ger den delsträng av aktuell sträng som börjar i position startindex och slutar i position endindex- ger en kopia av aktuell sträng där alla versaler har bytts ut mot gemener ger en kopia av aktuell sträng där alla gemener har bytts ut mot versaler ger en kopia av aktuell sträng där inledande och avslutande blanka tecken och tabulator-tecken tagits bortstring (String str) returnerar texten som motsvarar heltalet n 3 4
Exempel Några metoder i standardklassen Character int getnumericvalue(char ch) boolean isdigit(char ch) boolean isletter(char ch) boolean isletterordigit(char ch) boolean islowercase(char ch) boolean isuppercase(char ch) char tolowercase(char ch) char touppercase(char ch) ger Unicode för ch siffra, annars returneras värdet false bokstav, annars returneras värdet false siffra eller bokstav, annars returneras värdet false liten bokstav, annars returneras värdet false stor bokstav, annars returneras värdet false om ch är en stor bokstav returneras motsvarande lilla bokstav annars returneras ch om ch är en liten bokstav returneras motsvarande stora bokstav annars returneras ch Skriv ett Java-program som läser en mening från terminalen och räknar antalet vokaler, konsonanter och siffror. Analys: Indata: En sträng av godtyckliga tecken. Utdata: Utskrift av hur många vokaler, konsonanter respektive siffror som finns i den inlästa strängen. Exempel: Strängen Design: Algoritm: "xfgäåöabcdehi,%3" ger utskriften Antalet vokaler är 6 Antalet konstanter är 7 Antalet siffror är 3. Läs strängen str. Sätt antsiffror =, antvokaler = och antkonsonanter = 3. För varje tecken ch i strängen 3.. if (ch är en bokstav) if (ch är en vokal) antvokaler = antvokaler + ; antkonsonanter = antkonsonanter + ; if (ch är en siffra) antsiffror = antsiffror + ; 4. Skriv ut antvokaler, antkonsonanter och antsiffror Datarepresentation: str är av datatypen String antsiffror, antvokaler, antkonsonanter är av typen int. 5 6 Diskussion: Att löpa igenom varje tecken i strängen str är enkelt - det första tecknet i strängen finns i position, strängens längd erhålls mha metoden str.length() och tecknet i position j i strängen fås mha metoden str.charat(j). För att avgöra om ett tecken är en bokstav eller om ett tecken är en siffra finns de båda metoderna isletter respektive isdigit i klassen Character. Vårt egentliga problem är att ta reda på om ett tecken är en vokal! Vi skriver en metod för detta problem: public static boolean isvokal(char ch) Metoden vokal, annars returnerars värdet false. I metoden deklarerar vi en sträng som innehåller de bokstäver som är vokaler: String vokaler = "aeiouyåäö"; För att avgöra om tecknet ch är en vokal använder vi metoden indexof på strängen vokaler. Anropet vokaler.indexof(ch) ger värdet - om tecknet ch inte finns bland de tecken som ingår i strängen vokaler, annars ger anropet ett heltal större eller lika med. Eftersom strängen vokaler innehåller endast de "små" vokalerna, men ch givetvis kan vara en "stor" vokal måste ch översättas till sin "lilla" motsvarighet. Detta görs med metoden tolowercase som finns i klassen Character. Implementation: import javax.swing.*; public class Count { private static boolean isvokal(char ch) { String vokaler = "aeiouyåäö"; char smallch = Character.toLowerCase(ch); if (vokaler.indexof(smallch)!= -) return true; return false; //isvokal public static void main(string[] args) { while(true) { String indata = JOptionPane.showInputDialog("Ge en mening: "); if (indata == null) break; int antvokaler =, antkonsonanter =, antsiffror = ; for (int pos = ; pos < indata.length(); pos = pos + ) { char teck = indata.charat(pos); if (Character.isLetter(teck)) if (isvokal(teck)) antvokaler = antvokaler + ; antkonsonanter = antkonsonanter + ; if (Character.isDigit(teck)) antsiffror = antsiffror + ; JOptionPane.showMessageDialog(null, "Antalet vokaler är " + antvokaler + "\nantalet konsonanter är " + antkonsonanter + "\nantalet siffror är " + antsiffror); //while //main //Count 7 8
Flerdimensionella fält Förekommer ofta i verkliga livet. Flerdimensionella fält int[][] tabell = {{, 34, 7,9, {53, 43, 33, 68, {9,, 3, 4; 34 7 9 53 43 33 68 9 3 4 Flerdimensionella fält är fält av fält. int[][] tabell = new int[3][4]; tabell Eftersom ett flerdimensionellt fält är ett fält med referenser till ett endimensionellt fält, kan raderna vara olika långa int[][] tabell = {{, 34, 7,9, {53, 43, 33, {9, ; 34 7 9 53 43 33 9 9 Flerdimensionella fält int[][] tabell = {{, 34, 7,9, {53, 43, 33 {9, ; tabell[].length ger 4 tabell[].length ger 3 tabell[].length ger 34 7 9 53 43 33 9 Exempel Skriv ett program som läser in en NxN matris, samt avgör och skriver ut huruvida matrisen är symetrisk eller inte. Matrisens gradtal ges som indata. För en symetrisk matris A gäller att a ij = a ji för alla i och j Arrays.sort(tabell[]) sorterar rad i tabell Arrays.sort(tabell[]) sorterar rad i tabell Arrays.sort(tabell[]) sorterar rad i tabell 9 34 7 33 43 53 9
Analys: Indata: Ett gradtal samt en kvadratiskt matris med detta gradtal. Utdata: Utskrift av huruvida den inlästa matrisen är symetrisk eller inte. Exempel: Matrisen 3 3 4 3 4 5 ger utskriften MATRISEN ÄR SYMETRISK, medan matrisen 3 3 4 5 5 6 7 ger utskriften MATRISEN ÄR INTE SYME- TRISK, medan matrisen Design: Diskussion: När vi skall kontrollera om matrisen är symetrisk utgår vi från att så är fallet. För att handha denna kunskap sätter vi en boolsk variabel, som vi kan kalla okey till värdet true. Sedan genomlöper vi matriselementen och om vi då påträffar något element a ij för vilket det gäller att a ij a ji har vi en icke-symetrisk matris. Detta kommer vi ihåg genom att sätta okey till värdet false. Algoritm:. Läs gradtalet n. Läs matrisen a 3. okey = true; 4. För varje element a ij i matrisen a 4.. if (a(i,j) a(j,i)) okey = false; 5. if okey Skriv ut Matrisen är symetrisk.. Skriv ut Matrisen är INTE symetrisk.. Datarepresentation: A är av datatypen double[][]. 3 4 Implementation: import javax.swing.*; public class Symetrisk { public static void main(string[] args) { String indata; indata = JOptionPane.showInputDialog("Ange matrisens gradtal: "); int gradtal = Integer.parseInt(indata); double[][] matris = new double[gradtal][gradtal]; for (int rad = ; rad < gradtal; rad = rad + ) for (int kol = ; kol < gradtal; kol = kol + ) { indata = JOptionPane.showInputDialog( "Ge element (" + rad + ", " + kol + ")"); matris[rad][kol] = Double.parseDouble(indata); boolean okey = true; for (int rad = ; rad < gradtal; rad = i + ) for (int kol = ; kol < gradtal; kol = kol + ) if (matris[rad][kol]!= matris[kol][rad]) okey = false; if (okey) JOptionPane.showMessageDialog(null, Matrisen är symetrisk! ); JOptionPane.showMessageDialog(null, Matrisen är INTE symetrisk! ); // main // Symetrisk Alternativ implementation: Underprogram import javax.swing.*; public class Symetrisk { public static void main(string[] args) { String indata; indata = JOptionPane.showInputDialog("Ange matrisens gradtal: "); int gradtal = Integer.parseInt(indata); double[][] matris = readmatris(gradtal); if (issymetrisk(matris)) JOptionPane.showMessageDialog(null, Matrisen är symetrisk! ); JOptionPane.showMessageDialog(null, Matrisen är INTE symetrisk! ); // main public static double[][] readmatris(int grad) { double[][] matrisen = new double[grad][grad]; for (int rad = ; rad < grad; rad = rad + ) { for (int kol = ; kol < grad; kol = kol + ) { String indata = JOptionPane.showInputDialog( "Ge element (" + rad + ", " + kol + ")"); matrisen[rad][j] = Double.parseDouble(indata); return matrisen; // readmatris public static boolean issymetrisk(double[][] matris) { boolean okey = true; for (int rad = ; rad < matris.length; rad = rad + ) for (int kol = ; kol < matris[i].length; kol = kol + ) if (matris[rad][kol]!= matris[kol][rad]) okey = false; return okey; // Symetrisk 5 6
Alternativ implementation av metoden readmatris, med användning av ett Scanner-objekt: import java.util.*;... public static double[][] readmatris(int grad) { double[][] matrisen = new double[grad][grad]; String indata = JOptionPane.showInputDialog( "Ge element :"); Scanner sc = new Scanner(indata); for (int i = ; i < grad; i = i + ) { int j = ; while (j < grad) { if (sc.hasnextdouble()) { matrisen[i][j] = sc.nextdouble(); j = j + ; { indata = JOptionPane.showInputDialog( "Ge fler element :"); sc = new Scanner(indata); return matrisen; // readmatris Läsning och skrivning Att göra utskrifter är i Java oproblematiskt, men att läsa från tangentbordet (eller andra enheter) är inte lika lätt. Därför har vi hittills använt den dialogruta för inmatning som Swing tillhandahåller (JOptionPane.showDialog). Swing s dialogrutor kan dock ibland vara ganska "klumpiga" att använda. Av denna orsak brukar därför varje läroboksförfattare tillhandahålla ett eget paket för att underlätta inläsning. Detta är dock inte alltid så bra eftersom inläsningen då inte blir "standardiserad". Om man flyttar ett program som läser på ett ickestandardiserat sätt blir det problem, om man inte längre har tillgång till det paketet som innehåller de inläsningsrutiner som används i programmet. 7 8 Läsning och skrivning All läsning och skrivning i Java sker med användning av strömmar. En ström är ett enkelriktat flöde av data som strömmar in i eller ut från ett program, man skiljer således på inströmmar och utströmmar. Sändare Program data skriv data data data Strömmar Program Vad sändarna och mottagarna är kan variera. De kan t.ex. vara tangentbordet, skärmen, ett modem, en fil på sekundärminne, ett annat program eller andra delar av samma program. Programmet vet egentligen inte vad som finns i andra ändan av strömmen. läs data data Mottagare Utskrift till skärmen Data som skall skrivas ut på bildskärmen läggs i strömmen System.out. Nedan listas de medtoder som finns för att skriva till System.out: Metoder som skriver ett objekt eller variabel av angiven typ till utströmmen print(object), print(string), print(char[]); print(char), print(int), print(long), print(float), print(double), print(boolean) Metoder som skriver ett objekt eller variabel av angiven typ till utströmmen och avslutar med ett nyradstecken: println(object), println(string), println(char[]); println(char), println(int), println(long), println(float), println(double), println(boolean) Exempel: System.out.print("Vad heter du? "); En strängen skrivs inte ut direkt utan mellanlagras i en utdatabuffert. Bufferten kan tömmas med med hjälp av metoden flush. För att förvissa sig om att en utskrift som görs med metoden print skrivs ut direkt måste ett anrop av flush göras. Görs en utskrift däremot med printlnmetoden kommer utdatabufferten att tömmas automatiskt. 9
Inläsning från tangentbordet Data som skrivs på tangentbordet hamnar i strömmen System.in. Det går inte att läsa direkt från System.in utan denna ström måste först kopplas till en annan ström. System.in (InputStream) För att kunna läsa tecken och inte bytes kopplas strömmen System.in till ett objekt av klassen InputStreamReader, som finns i paketet java.io. Inläsningen blir effektivare om programmet läser in hela rader istället för att läsa tecken för tecken. Därför kopplas strömmen till ett objekt av klassen BufferedReader. I klassen BufferedReader finns bl.a. följande metoder String readline() int read() long skip(long n) (InputStreamReader) myin (BufferedReader) läser en rad läser ett tecken läser förbi ett antal tecken Samtliga dessa metoder reser IOException, som måste hanteras (på ett eller annat sätt)! Konstruktionen exceptions behandlas dock inte denna kurs. Inläsning av tal via tangentbordet Tyvärr innehåller inte klassen BufferedReader några metoder för att omvandla talsträngar till numeriska tal. Vid läsning av ett tal per rad kan omvandling mellan String och tal göras med användning av konerteringsmetoderna i respektive omslagsklass, t.ex. Integer.parseInt och Double.parseDouble. import java.io.*; public class Tal { public static void main (String[] arg) throws IOException { BufferedReader myin = new BufferedReader ( new InputStreamReader(System.in)); System.out.print("Skriv ett heltal: "); String textrad = myin.readline(); textrad = textrad.trim(); //Rensar bort blanktecken int heltal = Integer.parseInt(textRad); System.out.println("Talet är: " + heltal); System.out.print("Skriv ett reellt tal: "); textrad = myin.readline(); textrad = textrad.trim(); double reellt = Double.parseDouble(textRad); System.out.println("Talet är: " + reellt); //main //Tal Inläsning av flera tal på samma inmatningsrad Med användning av klassen Scanner är det möjligt att ge flera indatavärden på samma inmatningsrad. Nedanstående program visar hur detta görs när det standardiserade inläsningsförfarandet i Java används. import java.util.*; public class Adderare { public static void main (String[] arg) { Scanner sc = new Scanner (System.in); double summa =.; System.out.print("Ge talen: "); while(sc.hasnextdouble()) { double etttal = sc.nextdouble(); summa = summa + etttal; System.out.println("Summan blir: " + summa); //main //Adderare Observera att inmatningen avslutas med ctrl-z på en tom inmatningsrad. 3