Strängar har vi använt i nästan alla våra laborationer redan, då det är en av de grundläggande datatyperna i javascript, och det är svårt att göra något intressant alls utan strängar. Nu skall vi dock se lite mer på vad man kan göra med strängar.
En sträng (“string” på engelska) är en sekvens av tecken, alltså en lista av tecken. Därför har strängar en del likheter med arrayer, men också viktiga skillnader. Det är inte alls lika vanligt att vilja komma åt enskilda tecken i en sträng och ändra dem som det är med arrayer. Istället är det vanligare att man vill bearbeta hela strängen på olika sätt, eller hitta delsträngar.
0 - Skapa en arbetsmapp och förbered filerna
Innan du börjar, skapa en ny labb-mapp som du kan kalla lab-3c där du sparar filerna för just den här laborationen.
Skapa en fil index.html med innehållet nedan och en tom script.js och öppna sedan sidan med Live Server:
<!DOCTYPE html>
<html>
<head>
<title>Strängar</title>
<script type="module" src="script.js"></script>
</head>
<body>
<h1>Strängar</h1>
<p>Öppna webbläsarens konsol (F12 → Console)</p>
</body>
</html>
1 - Likheter med arrayer
En sträng är som sagt en sekvens av tecken, och precis som arrayer är strängar indexerade från 0. Det betyder att vi kan läsa tecken i en sträng med hjälp av index, precis som med arrayer. Vi kan också använda egenskapen length för att få reda på hur många tecken en sträng innehåller.
Lägg till följande i script.js:
let text = "May the force be with you";
console.log("Text:", text);
console.log("Fösta tecknet:", text[0]); // M
console.log("Tredje tecknet:", text[2]); // y
Med strängar kan vi dock inte ändra enstaka tecken genom indexering, som vi kan med arrayer. Testa att lägga till följande rad i script.js:
text[1] = "o";
console.log("Uppdaterad text?:", text);
Det fungerar inte, strängen förblir oförändrad. Det är för att strängar är oföränderliga i JavaScript. Om vi vill ändra en sträng måste vi skapa en ny sträng.
length
Precis som arrayer har strängar en egenskap som heter length som berättar hur många tecken strängen innehåller. Lägg till följande i script.js:
console.log("Längden på text:", text.length);
Hitta i en sträng
Både includes och indexOf fungerar på strängar på samma sätt som på arrayer. Men i strängar söker vi efter delsträngar istället för enskilda värden.
includes: Returnerartrueom delsträngen finns i texten, annarsfalse.indexOf: Returnerar indexet där delsträngen startar, eller -1 om delsträngen inte finns.
I script.js, lägg till följande:
if (text.includes("force")) { // Sök efter "force" i strängvariabeln text
console.log( "'force' ingår i texten" );
}
else {
console.log( "'force' ingår ej i texten" );
}
let i = text.indexOf("fourth"); // Sök efter "fourth" i strängvariabeln text
// Resultatet blir positionen där "fourth" börjar. Om "fourth" ej finns, blir resultatet -1.
if (i === -1) {
console.log( "'fourth' finns ej i texten" );
}
else {
console.log( "'fourth' börjar på position " + i );
}
Testa:
- Skapa en egen strängvariabel med en mening du gillar, högst upp i
script.js.- Logga ut längden av strängen.
- Uppdatera if-satserna ovan med att söka i din strängvariabel efter delsträngar som både finns och inte finns.
2 - Strängvärden och speciella tecken
Strängar skapas genom att omge text med antingen dubbla citattecken (") eller enkla citattecken ('). Båda fungerar lika bra, men du måste vara konsekvent och använda samma typ av citattecken i början och slutet av strängen.
let singleQuoteString = 'Detta är en sträng med enkla citattecken.';
let doubleQuoteString = "Detta är en sträng med dubbla citattecken.";
console.log(singleQuoteString);
console.log(doubleQuoteString);
Om du vill använda samma typ av citattecken inuti strängen som du använder för att skapa den, måste du “escape:a” dem med ett backslash (\). Men den andra typen av citattecken kan du använda utan problem:
let quoteString = "Han sa: \"JavaScript är kul!\"";
let quoteString2 = 'Han sa: "JavaScript är kul!"';
console.log(quoteString);
console.log(quoteString2);
Du behöver också använda backslash för att representera vissa speciella tecken i strängar, som ny rad (\n), tabb (\t), eller backslash självt (\\):
let specialString = "Första raden.\nAndra raden.\tMed en tabb och backslash i slutet\\";
console.log(specialString);
3 - Operatorer för strängar
Som vi har sett och använt i tidigare laborationer så finns det vissa operatorer som fungerar på strängar.
Sammanslagning av strängar
Den vanligaste operatorn som fungerar på strängar är + som används för att konkatenera (sammanfoga) strängar. Den finns också i en förkortad version +=, som lägger till en sträng i slutet av ett befintligt strängvärde.
Lägg till följande i script.js för att se hur du kan slå ihop strängar med + för att skapa en ny sträng:
let favoriteLanguage = "JavaScript";
let message = "Mitt favoritspråk i hela världen är " + favoriteLanguage + "!";
console.log(message);
Du kan sätta ihop hur många delar du vill med +-operatorn, och värden som inte är strängar konverteras automatiskt till strängar.
let year = 2025;
let name = "Rut-Inger";
let greeting = "Gott nytt år " + name + "! Ha ett bra " + year + "!";
console.log(greeting);
Med += kan du som sagt lägga till text i slutet av en befintlig strängvariabel. Det är extra praktiskt när du vill bygga upp en sträng i flera steg, till exempel i en loop.
Lägg till följande i script.js:
let friends = ["Anna", "Bertil", "Cecilia", "David", "Eva"];
let guestList = "Gäster: Mamma, Pappa";
for (let name of friends) {
guestList += ", " + name;
}
console.log(guestList);
Ett vanligt användsområde är att bygga upp HTML-kod som en sträng, som man sedan kan lägga in i en webbsida, som i följande exempel. Kopiera till script.js:
let code = "<ul>"
for(let name of friends) {
code += "<li>" + name + "</li>";
}
code += "</ul>"
document.querySelector("body").innerHTML += code;
Testa:
- Skapa egna variabler med text eller tal och sätt ihop dem till en lång sträng med
+.- Använd
+=för att bygga upp en sträng i flera steg, till exempel en lista med dina favoritfilmer eller liknande.- Använd samma teknik för att skapa html-kod utifrån en lista. Ugå från en lista med färger och skapa en knapp för varje färg, texten på knappen skall vara färgens namn. Använd
+=för att lägga till html-koden i slutet avbody, som i exempel ovan.
Mallade strängar (även kallade “template literals”)
Det finns ett annat, smidigare(?), sätt att skapa strängar som innehåller variabler och uttryck, så kallade mallade strängar eller template literals. De skapas med backticks (aka. grav accent) (`) istället för vanliga citattecken. Inuti en mallad sträng kan du använda ${...} för att infoga variabler eller uttryck.
console.log(`Hej ${name}, välkommen till år ${year+1}!`);
En annan fördel med mallade strängar är att de kan sträcka sig över flera rader, utan att du behöver använda \n. Lägg till följande i script.js:
let welcomeMessage = `Hej ${name}!
Välkommen till vår webbplats.
Vi hoppas du får en trevlig vistelse.`;
console.log(welcomeMessage);
Testa: Skapa en egen mallad sträng som innehåller både variabler och uttryck. Logga ut den till konsolen.
Jämförelse av strängar
Likhet mellan strängar kan kollas med den vanliga jämförelseoperatorn ===. Men strängarna behöver vara exakt lika för att räknas som lika, skillnad på versaler och gemener spelar roll, liksom mellanslag och andra tecken.
console.log('"apple" === "apple"', "apple" === "apple"); // true
console.log('"apple" === " apple"', "apple" === " apple"); // false, extra mellanslag
console.log('"apple" === "Apple"', "apple" === "Apple"); // false, skillnad på versaler och gemener
Därför är det ofta bra att normalisera strängar innan man jämför dem, till exempel genom att ta bort onödiga mellanslag med trim() och göra alla tecken till gemener med toLowerCase(). Det kommer ett exempel på det nedan.
4 - Läsa ut delsträngar
Ett vanligt behov är att kunna läsa ut delar av en sträng, så kallade delsträngar. Det kan vi göra med metoden substring(startIndex, endIndex), där startIndex är det index där delsträngen börjar (inklusive detta tecken) och endIndex är det index där delsträngen slutar (exklusive detta tecken).
Lägg till följande i script.js:
let part = text.substring(8, 13);
console.log("Delsträng från index 8 till 13:", part);
Testa: Ändra argumenten till
substringför att läsa ut andra delar av strängen.
- Kan du läsa ut ordet “with”?
Det går att använda substring med bara ett argument också, då läser den ut från det indexet till slutet av strängen:
Fortsätt i script.js med följande:
let ending = text.substring(14);
console.log("Slutet av strängen, med början på index 14:", ending);
Testa: Använd
substringpå din egen strängvariabel för att läsa ut olika delar av den.
- Kan du läsa ut det första ordet?
- Kan du läsa ut de sista fem tecknen?
5 - Skapa varianter av strängar
En annan vanlig sak att göra med strängar är att skapa varianter av dem, till exempel med versaler eller gemener, eller genom att ta bort onödiga mellanrum i början och slutet. Detta behöver ofta göras när man till exempel hanterar användarinmatning för att kunna jämföra strängar på ett kontrollerat sätt.
Testa metoderna toLowerCase, toUpperCase och trim genom att lägga till följande i script.js:
let userInput = " JaVaScRiPt ";
console.log("Original användarinmatning:", `"${userInput}"`);
let lowercase = userInput.toLowerCase();
console.log("Efter toLowerCase:", `"${lowercase}"`);
let uppercase = userInput.toUpperCase();
console.log("Efter toUpperCase:", `"${uppercase}"`);
let trimmed = userInput.trim();
console.log("Efter trim:", `"${trimmed}"`);
let normalized = trimmed.toLowerCase();
console.log("Efter trim och toLowerCase:", `"${normalized}"`);
6 - Hantera användarinmatning
Slutigen skall vi bygga upp ett konkret exempel där vi använder dessa strängmetoder för att på ett robust sätt kunna hantera användarinmatning.
Börja med att kommentera bort all kod i som lägger in html-kod i body, så att vi har en ren sida igen.
Därefter kan du lägga in följande i index.html, precis ovanför slutet av body:
<hr>
<p>Kan du namnen på kursansvariga?</p>
<label for="nameInput">Namn:</label>
<input type="text" id="nameInput" />
<button id="checkNameButton">Gissa</button>
<h2>Gissningar</h2>
<ul id="guesses"></ul>
I script.js behöver vi nu lägga till kod för att hantera knapptryckningen och kontrollera användarens gissning. Men först behöver vi en lista med godkända namn. Lägg till följande högst upp i script.js:
const validNames = [
"niklas",
"kalle",
"henrik",
"rebecca",
"romain"
];
Däefter är det en bra idé att hämta referenser till de html-element vi behöver arbeta med. Input-elementet kan du hämta på följande sätt:
const nameInput = document.getElementById("nameInput");
Hämta även knappen och listan med id guesses på liknande sätt och spara dem i variabler checkNameButton respektive guessesList.
Därefter behöver vi lägga till en eventlyssnare för klick på knappen.
checkNameButton.addEventListener("click", function() {
// Kod för att hantera gissningen kommer här
});
Tanken är att här ta den inmatade texten, se om den matchar något av namnen i validNames, och sedan lägga till ett nytt listobjekt i guessesList som berättar om gissningen var rätt eller fel.
Vi kan börja med att ta den inmatade texten utan någon bearbetning.
let guess = nameInput.value;
Försök därefter själv att göra en if-sats som använder validNames.includes(guess) för att kolla om gissningen är rätt. Om den är rätt, skapa html-kod för ett li-element med texten "Rätt! {gissning} är en av oss.", annars använder du texten "Fel! {gissning} är inte ansvarig för någon kurs.". Lägg slutligen in det nya html-koden genom att använda += på guessesList.innerHTML.
Förslag på lösning
checkNameButton.addEventListener("click", function() {
let guess = nameInput.value;
if (validNames.includes(guess)) {
guessesList.innerHTML += `<li>Rätt! ${guess} är en av oss.</li>`;
}
else {
guessesList.innerHTML += `<li>Fel! ${guess} är inte ansvarig för någon kurs.</li>`;
}
});
Om du testar koden nu, så kommer den fungera om du skriver in namnen exakt som i validNames, men om du skriver in dem med versaler eller extra mellanslag så kommer det inte att fungera. För att fixa det, behöver vi normalisera gissningen innan vi jämför den.
Lägg till en rad efter att vi sparat gissningen i guess där du skapar en ny variabel normalizedGuess:
let normalizedGuess = guess.trim().toLowerCase()
Använd sedan normalizedGuess i if-satsen istället för guess.
Prova att köra igen. Nu skall det fungera oavsett om du skriver in namnen med versaler eller extra mellanslag.
Utmaning
- Undersök en sökväg
- Skapa en strängvariabel
pathmed följande väde:img/R2D2.png - Använd
indexOfför att hitta positionen för/och.. Spara dessa i separata variabler. - Använd de index du hittade för att läsa ut och logga:
- Katalog-namnet (dvs.
img) - filnamnet utan sökväg och filändelse (dvs.
R2D2)
- Katalog-namnet (dvs.
- Skapa en strängvariabel