Mere om tegnstrenge, StringBuffer

matfys.kvl.dk

Mere om tegnstrenge, StringBuffer

Programmering 2004

Forelæsning 6, fredag 24. september 2004

Mere om tegnstrenge

StringBuffer: effektivt udvidelige tegnstrenge.

Programmering 2004 KVL Side 6-1

Tegnstrenge og tegn

Tegnstrenge er instanser af klassen String.

Man skriver tegnstrenge i programteksten i dobbelte anførselstegn:

"Ole Hansen" "A38" "117" ""

Tegn er værdier af den simple type char og skrives i enkelte anførselstegn:

’O’ ’l’ ’e’ ’ ’ ’1’

En tegnstreng er en sekvens af tegn.

Nogle specialtegn: ’\n’ er linieskift, ’\t’ er tabulatortegn (’\\’ er \).

I datamaten repræsenteres hvert tegn ved et lille heltal, f.eks. 65 for ’A’.

En tegntabel er en ‘oversættelse’ fra kode (heltal i maskinen) til tegn (grafik på skærmen eller papiret).

Nogle standard tegntabeller: ASCII (i USA), ISO Latin1 (i vesteuropa), Unicode (hele verden).

Java anvender Unicode tegntabellen internt.

MSDOS-vinduet anvender et IBM tegnsæt (typisk IBM codepage 850).

Derfor bliver danske tegn ikke skrevet rigtigt ud i MSDOS-vinduet med f.eks.

System.out.println("blåbærgrød")

Programmering 2004 KVL Side 6-2

Den indbyggede klasse String

Antag s1 og s2 er variable af type String (erklæret med String s1, s2;).

Metoder: operationer på tegnstrenge

s1.length() er længden af s1, dvs. antallet af tegn.

s1.charAt(5) er tegnet ved indeks 5 i s1 (første tegn er indeks 0).

s1.equals(s2) er true hvis s1 og s2 indeholder de samme tegn, ellers false.

s1.equalsIgnoreCase(s2) som ovenfor, men store og små bogstaver regnes ens.

s1.compareTo(s2) er nul hvis ens; negativ hvis s1 mindre end s2; positiv ellers.

s1.substring(a, b) er delstrengen s1[a..b-1].

s1.substring(a) er delstrengen s1[a..s1.length()-1].

HUSK: Man kan ikke sammenligne tegnstrenge med de almindelige sammenligningsoperatorer

(==, !=, , =).

Programmering 2004 KVL Side 6-3

Eksempel på brug af tegnstrenge og opdeling af problem i metoder: Matchning af DNA-sekvenser

Et stykke DNA kan opfattes som en sekvens AGCCTGAAG af nukleotider.

Et nukleotid kan opfattes som et bogstav: ’A’, ’T’, ’C’, ’G’.

Et stykke DNA kan dermed repræsenteres som en tegnstreng.

Når man kortlægger en organismes genetiske materiale, finder man en række overlappende DNA fragmenter.

En gang i mellem er et nukleotid ubestemt (af eksperimentelle årsager).

Lad ’N’ betegne et ubestemt nukleotid: en vilkårlig af A, T, C, eller G.

Den typiske længde af et fragment er 200–300 nukleotider.

Overlappets længde er normalt ukendt.

Programmering 2004 KVL Side 6-4


Start på en klasse til at repræsentere DNA

public class DNA {

private final String sequence;

}

public DNA(String sequence) {

this.sequence = sequence;

}

public String toString() {

return sequence;

}

// Return new DNA sequence consisting of prefix of this DNA sequence

public DNA prefix(int length) {

return new DNA(sequence.substring(0,length));

}

// Return new DNA sequence consisting of suffix of this DNA sequence

public DNA suffix(int length) {

return new DNA(sequence.substring(sequence.length()-length));

}

// ... flere metoder senere

Programmering 2004 KVL Side 6-5

Test af prefix og suffix

public class TestDNA1 {

public static void main(String [] args) {

DNA d1 = new DNA("CNGAGCCTGCNAGCTGANCGTG");

}

}

System.out.println("d1: " + d1);

System.out.println("prefix 8 long: " + d1.prefix(8));

System.out.println("suffix 8 long: " + d1.suffix(8));

Programmering 2004 KVL Side 6-6

Det længste matchende overlap mellem to DNA-sekvenser

Match bagenden (suffiks) af et fragment med forenden (præfiks) af det næste.

...CNGAGCCTGCNAGCTGANCGTG

TAGNTGANCGTGCGGCGGTGGCGGA...

Det længste matchende overlap er

TAGCTGANCGTG

På grund af N (der matcher hvad som helst) behøver delsekvenserne ikke være identiske for at matche.

Vi designer løsningen “bottom up”, dvs. starter med at løse delproblemer:

1. Undersøg om to enkelte nukleotider matcher.

2. Undersøg om to sekvenser af samme længde matcher.

3. Find længste suffix af en sekvens der matcher prefix af en anden.

Programmering 2004 KVL Side 6-7

Matching af to nukleotider

Bogstaverne kan matche på følgende måde, hvor ’X’ står for mismatch:

A T C G N

A A X X X A

T X T X X T

C X X C X C

G X X X G G

N A T C G N

Metode nucleotideMatch, find match mellem to nukleotider efter ovenstående tabel:

private static char nucleotideMatch(char n1, char n2) { ... }

Programmering 2004 KVL Side 6-8


Match mellem to nucleotider n1 og n2

public class DNA {

// ...

}

// Match two nucleotides, return resulting nucleotide or ’X’ for mis-match

private static char nucleotideMatch(char n1, char n2) {

if (n1 == n2)

return n1;

else if (n1 == ’N’)

return n2;

else if (n2 == ’N’)

return n1;

else

return ’X’;

}

// ...

Programmering 2004 KVL Side 6-9

Find match mellem to DNA sekvenser

Givet to DNA-sekvenser af samme længde, find deres match.

Idé:

Tjek alle nukleotider i de to sekvenser fra venstre mod højre.

Så snart et mismatch ’X’ findes, ved vi at de to sekvenser ikke matcher.

Hvis vi derimod når til enden uden et mismatch, så matcher sekvenserne.

I dette tilfælde skal resultatet være match’et mellem de to sekvenser; ellers skal det være null.

Metode matches, find match mellem denne sekvens og en anden:

public DNA matches(DNA other) { ... }

Programmering 2004 KVL Side 6-10

public class DNA {

// ...

}

// Match this DNA sequence to another, return matched sequence (if match),

// return null for no match.

public DNA matches(DNA other) {

int length = sequence.length();

if (length != other.sequence.length())

return null; // Not same length

String matchedSeq = "";

for (int i = 0; i < length; i++ ) {

char match = nucleotideMatch(sequence.charAt(i),

other.sequence.charAt(i));

if (match == ’X’)

return null; // Mismatch

matchedSeq = matchedSeq + match;

}

return new DNA(matchedSeq);

}

// ...

Programmering 2004 KVL Side 6-11

Test af matches

public class TestDNA2 {

public static void main(String [] args) {

DNA d1 = new DNA("NAGCTGAN");

DNA d2 = new DNA("TAGNTGAN");

DNA d3 = new DNA("TAGTTGAN");

}

}

System.out.println("d1: " + d1);

System.out.println("d2: " + d2);

System.out.println("d3: " + d3);

System.out.println("d1 matched to d2: " + d1.matches(d2));

System.out.println("d1 matched to d3: " + d1.matches(d3));

Programmering 2004 KVL Side 6-12


Find det længste matchende overlap mellem to DNA-sekvenser

Et matchende overlap er et match mellem et suffiks af den ene sekvens og et præfiks af den anden.

Idé:

Prøv alle mulige overlap mellem suffikser af "denne" sekvens og præfikser af den anden.

Overlappet kan ikke være længere end den korteste af sekvenserne.

Start med at prøve det længste mulige overlap.

Hvis det fejler (matches giver null), så prøv et kortere overlap, osv.

Når et matchende overlap findes, stoppes. Det er det længste matchende overlap.

Metode maxOverlap, find det længste matchende overlap mellem "denne" og en anden DNA sekvens:

public DNA maxOverlap(DNA other) { ... }

Programmering 2004 KVL Side 6-13

public class DNA {

// ...

}

// Find longest overlap of the suffix of this DNA sequence against the

// prefix of another DNA sequence. Return null for no match.

public DNA maxOverlap(DNA other) {

int overlapLength = Math.min( sequence.length(),

other.sequence.length() );

DNA overlap = null;

while (overlapLength > 0 && overlap == null) {

overlap =

suffix(overlapLength).matches(other.prefix(overlapLength));

overlapLength--;

}

return overlap;

}

// ...

(Denne metode er simpel men ikke specielt effektiv; der dannes to nye DNA sekvenser for hvert suffix/prefix der

prøves.)

Programmering 2004 KVL Side 6-14

Test af maxOverlap

public class TestDNA3 {

public static void main(String [] args) {

DNA d1 = new DNA("CNGAGCCTGCNAGCTGANCGTG");

DNA d2 = new DNA("TAGNTGANCGTGCGGCGGTGGCGGA");

}

}

System.out.println("d1: " + d1);

System.out.println("d2: " + d2);

System.out.println("d1 overlap with d2: " + d1.maxOverlap(d2));

System.out.println("d2 overlap with d1: " + d2.maxOverlap(d1));

Programmering 2004 KVL Side 6-15

Fordele ved opdeling i metoder

Programmet er opdelt i metoder der kan forstås en ad gangen.

Derved kan programmet bedre forstås lidt ad gangen.

Find match mellem to nukleotider (A, C, T, G, N); ellers X:

private static char nucleotideMatch(char n1, char n2) { ... }

Find ud af om en anden sekvens matcher, ellers null:

public DNA matches(DNA other) { ... }

Find det længste overlap med en anden sekvens; ellers null:

public DNA maxOverlap(DNA other) { ... }

Programmering 2004 KVL Side 6-16


Problem med matches metoden: gradvis udvidelse af en String er langsom

Eksempel: Udførelse af

String s = "";

s = s + ’A’;

s = s + ’B’;

s = s + ’C’;

...

s = s + ’Z’;

skaber 26 midlertidige strenge A, AB, ABC, ..., ABC...Z.

Det endelige resultat har længde 26.

Der er kopieret 1 + 2 + 3 +···+26 = 26·27

2 = 351 tegn for at danne resultatet.

Generelt: hvis resultatet har længde n, så er der blevet kopieret n(n+1)

2

tegn.

Eksempel: Når n er 300, er der kopieret ca. 45000 tegn.

Med StringBuffer kan det meste af denne kopiering undgås.

Programmering 2004 KVL Side 6-17

StringBuffer: effektivt udvidelige tegnstrenge

En String forbliver for altid den samme, når den én gang er skabt.

Strengsammensætning (konkatenering) skaber en helt ny streng.

Derfor er gradvis udvidelse af en String meget langsommelig.

En StringBuffer er en streng som kan udvides effektivt.

Konstruktorer i StringBuffer

new StringBuffer() laver en ny tom StringBuffer.

new StringBuffer(117) laver en ny tom StringBuffer med plads til 117 tegn.

Det er mest effektivt at lave en StringBuffer stor nok fra begyndelsen.

Metoder i StringBuffer

sb.append(c) tilføjer tegnet c bagest i bufferen sb.

sb.length() giver det aktuelle antal tegn i bufferen.

sb.charAt(i) giver tegnet på plads i, somforenString.

sb.setCharAt(i, c) sætter plads i lig med tegnet c.

sb.toString() giver en String bestående af alle tegnene fra bufferen sb.

Programmering 2004 KVL Side 6-18

En udgave af matches med StringBuffer:

public class DNA {

// ...

}

// Match this DNA sequence to another, return matched sequence (if match),

// return null for no match.

public DNA matches(DNA other) {

int length = sequence.length();

if (length != other.sequence.length())

return null; // Not same length

StringBuffer matchedSeq = new StringBuffer(length);

for (int i = 0; i < length; i++ ) {

char match = nucleotideMatch(sequence.charAt(i),

other.sequence.charAt(i));

if (match == ’X’)

return null; // Mismatch

matchedSeq.append(match);

}

return new DNA(matchedSeq.toString());

}

// ...

Programmering 2004 KVL Side 6-19

Nyt idag

• Tegnstrenge: sammenligning, udtagelse af tegn, udtagelse af delstrenge.

• Gradvis udvidelse af en String er tidskrævende.

• En StringBuffer kan udvides effektivt.

Læsning for idag: Morelli kapitel 7

Programmering 2004 KVL Side 6-20

More magazines by this user
Similar magazines