Strings #
Strings are the most frequently used data type in almost every Python program — from validating user input, formatting output, to processing data from files and APIs. Python provides two layers of tools for working with strings: built-in methods directly available on every str object, and the string module containing extra constants and utilities. Understanding both will make you far more efficient when processing text.
Text Transformation Methods #
Methods in this group change the form or capitalization of a string. It’s important to understand: all string methods in Python return a new string — the original string is unchanged because strings are immutable.
teks = "hello world"
print(teks.upper()) # "HELLO WORLD"
print(teks.lower()) # "hello world"
print(teks.capitalize()) # "Hello world" -- first letter only
print(teks.title()) # "Hello World" -- first letter of each word
print(teks.swapcase()) # "HELLO WORLD" -- reverse capitalization
# The original string is unchanged
print(teks) # "hello world"
title() has one behavior worth noting — it treats non-letter characters as word separators:
print("it's a test".title()) # "It'S A Test" -- apostrophe treated as a separator
print("2nd place".title()) # "2Nd Place" -- digits treated as a separator
If you need smarter capitalization, use string.capwords() from the string module (covered in the next section).
Search and Position-Checking Methods #
These methods are used to find whether a substring exists or get its position.
kalimat = "belajar python itu menyenangkan"
# Find a substring's position
print(kalimat.find("python")) # 8 -- index of the first occurrence
print(kalimat.find("java")) # -1 -- not found, returns -1
print(kalimat.rfind("a")) # 28 -- search from the right
# index() is similar to find(), but raises ValueError when not found
print(kalimat.index("python")) # 8
# kalimat.index("java") # ValueError: substring not found
# Check prefixes and suffixes
print(kalimat.startswith("belajar")) # True
print(kalimat.endswith("menyenangkan")) # True
# Count substring occurrences
print(kalimat.count("a")) # 4
Usefind()when you’re not sure the substring exists — it returns-1when not found. Useindex()only when you’re sure the substring exists and want an error immediately if it doesn’t.
Cleaning and Replacement Methods #
Used to clean input of excess whitespace or replace parts of a string.
# strip() -- remove characters at both ends (default: spaces)
kotor = " hello world "
print(kotor.strip()) # "hello world"
print(kotor.lstrip()) # "hello world "
print(kotor.rstrip()) # " hello world"
# strip() can take an argument of characters to remove
path = "///usr/bin///"
print(path.strip("/")) # "usr/bin"
# replace() -- replace a substring
teks = "belajar java, java itu susah"
print(teks.replace("java", "python")) # "belajar python, python itu susah"
print(teks.replace("java", "python", 1)) # "belajar python, java itu susah" -- max 1 replacement
Python 3.9 and later add two very useful new methods:
# removeprefix() and removesuffix() -- Python 3.9+
filename = "IMG_20240101.jpg"
print(filename.removesuffix(".jpg")) # "IMG_20240101"
print(filename.removeprefix("IMG_")) # "20240101.jpg"
# ANTI-PATTERN: people used to do this
# if filename.endswith(".jpg"):
# filename = filename[:-4] -- error-prone index math
# CORRECT: use removesuffix()
# filename = filename.removesuffix(".jpg")
Splitting and Joining Methods #
split() and join() are a pair often used together to process text-shaped data.
# split() -- split a string into a list
kalimat = "satu dua tiga empat"
print(kalimat.split()) # ['satu', 'dua', 'tiga', 'empat']
print(kalimat.split(" ", 2)) # ['satu', 'dua', 'tiga empat'] -- max 2 splits
csv_baris = "Alice,25,Jakarta"
print(csv_baris.split(",")) # ['Alice', '25', 'Jakarta']
# splitlines() -- split by newline
multiline = "baris satu\nbaris dua\nbaris tiga"
print(multiline.splitlines()) # ['baris satu', 'baris dua', 'baris tiga']
# join() -- join a list into a string
kata = ["belajar", "python", "itu", "seru"]
print(" ".join(kata)) # "belajar python itu seru"
print(", ".join(kata)) # "belajar, python, itu, seru"
print("".join(kata)) # "belajarpythonitueru"
# partition() -- split into 3 parts: before, separator, after
url = "https://python.unisbadri.com/basic/variable/"
proto, sep, rest = url.partition("://")
print(proto) # "https"
print(rest) # "python.unisbadri.com/basic/variable/"
# rpartition() -- same but starting from the right
path = "/home/user/dokumen/laporan.pdf"
dir_path, sep, filename = path.rpartition("/")
print(filename) # "laporan.pdf"
join()is far more efficient than concatenating strings with+inside a loop. Use"".join(list_of_strings)to build a string from many parts.
String Validation Methods #
Methods that return True or False to check a string’s content. Useful for input validation before further processing.
# Check character types
print("hello".isalpha()) # True -- all letters
print("hello1".isalpha()) # False -- contains a digit
print("12345".isdigit()) # True -- all digits
print("12.5".isdigit()) # False -- a dot isn't a digit
print("hello1".isalnum()) # True -- letters or digits
print("hello!".isalnum()) # False -- contains an exclamation mark
print(" ".isspace()) # True -- all spaces/whitespace
# Check capitalization
print("hello".islower()) # True
print("HELLO".isupper()) # True
print("Hello World".istitle()) # True
A simple input validation example:
def validasi_usia(input_user: str) -> int:
# ANTI-PATTERN: direct conversion without validation
# return int(input_user) -- crashes if the input isn't a number
# CORRECT: validate first
nilai = input_user.strip()
if not nilai.isdigit():
raise ValueError(f"Age must be a number, not '{nilai}'")
return int(nilai)
Alignment and Padding Methods #
Used to format output neatly, especially when displaying tables or reports in the terminal.
teks = "Python"
# Alignment with a given width
print(teks.center(20)) # " Python "
print(teks.ljust(20)) # "Python "
print(teks.rjust(20)) # " Python"
# You can specify a fill character
print(teks.center(20, "-")) # "-------Python-------"
print(teks.ljust(20, ".")) # "Python.............."
# zfill() -- left zero-padding, specifically for numbers
kode = "42"
print(kode.zfill(5)) # "00042"
print("-42".zfill(5)) # "-0042" -- the minus sign stays on the left
String Formatting #
Python has three ways to format strings. Each has a different usage context.
f-strings (Recommended, Python 3.6+) #
nama = "Budi"
usia = 28
saldo = 1250000.5
# Insert variables directly
print(f"Hello, {nama}! You are {usia} years old.")
# Number formatting
print(f"Balance: Rp{saldo:,.2f}") # "Balance: Rp1,250,000.50"
print(f"Percentage: {0.857:.1%}") # "Percentage: 85.7%"
print(f"Width 10: {nama:>10}") # " Budi"
print(f"Width 10: {nama:<10}") # "Budi "
print(f"Width 10: {nama:^10}") # " Budi "
# Expressions inside f-strings
print(f"Next year: {usia + 1} years")
print(f"Uppercase: {nama.upper()}")
# Debug print (Python 3.8+) -- very useful
x = 42
print(f"{x=}") # "x=42"
str.format() (Python 2/3 compatibility) #
# ANTI-PATTERN: use format() for new code
template = "Hello, {}! You are {} years old."
print(template.format("Budi", 28))
# Use f-strings instead for new code
# print(f"Hello, {nama}! You are {usia} years old.")
# format() is still relevant for templates stored as strings
pesan_template = "Welcome, {nama}! Your role: {role}."
print(pesan_template.format(nama="Andi", role="admin"))
% formatting (Legacy, avoid for new code) #
# ANTI-PATTERN: old style, avoid in modern Python code
print("Hello, %s! You are %d years old." % ("Budi", 28))
# CORRECT: use f-strings
nama, usia = "Budi", 28
print(f"Hello, {nama}! You are {usia} years old.")
f-strings are the top choice for Python 3.6+. Usestr.format()only when you need to store a template as a string to be formatted later. Avoid%formatting in new code.
The string Module
#
The string module provides character constants and utilities useful for advanced text operations.
Character Constants #
import string
print(string.ascii_lowercase) # 'abcdefghijklmnopqrstuvwxyz'
print(string.ascii_uppercase) # 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
print(string.ascii_letters) # lower + upper combined
print(string.digits) # '0123456789'
print(string.hexdigits) # '0123456789abcdefABCDEF'
print(string.octdigits) # '01234567'
print(string.punctuation) # '!"#$%&\'()*+,-./:;<=>?@[\\]^_`{|}~'
print(string.whitespace) # spaces, tabs, newlines, etc.
print(string.printable) # all printable characters
Real use of these constants — for example, making a password generator or character validator:
import string
import secrets
def buat_password(panjang: int = 16) -> str:
"""Generate a strong random password."""
karakter = string.ascii_letters + string.digits + string.punctuation
return "".join(secrets.choice(karakter) for _ in range(panjang))
def hanya_alfanumerik(teks: str) -> bool:
"""Check whether a string contains only letters and digits."""
karakter_valid = string.ascii_letters + string.digits
return all(c in karakter_valid for c in teks)
print(buat_password()) # example: "xK#8mP2@nL5qR9!w"
print(hanya_alfanumerik("hello123")) # True
print(hanya_alfanumerik("hello!")) # False
string.capwords()
#
Unlike str.title(), the capwords() function is more consistent because it doesn’t treat punctuation as word separators:
import string
# ANTI-PATTERN: title() has issues with apostrophes
print("it's a test".title()) # "It'S A Test" -- wrong!
# CORRECT: capwords() is more consistent
print(string.capwords("it's a test")) # "It's A Test"
# capwords() also removes excess whitespace
print(string.capwords(" hello world ")) # "Hello World"
string.Template
#
Template is useful for creating text templates whose placeholders can be filled in later, especially when you don’t want to execute arbitrary expressions from user input:
from string import Template
# Create a template with $variable placeholders
surat = Template("""
Dear $nama,
We are pleased to inform you that your registration
with ID $id_pendaftaran has been successfully confirmed.
Best regards,
The $organisasi Team
""")
# Fill in the template
print(surat.substitute(
nama="Budi Santoso",
id_pendaftaran="REG-2024-001",
organisasi="Python Indonesia"
))
# safe_substitute() -- doesn't crash if a placeholder is left unfilled
template_parsial = Template("Hello $nama, your code: $kode")
print(template_parsial.safe_substitute(nama="Andi"))
# "Hello Andi, your code: $kode" -- $kode is left as-is
Don’t use f-strings for templates whose placeholders come from untrusted user input. Usestring.Templateorstr.format_map()to be safer, since they don’t execute arbitrary Python expressions.
Summary #
- Strings are immutable — all methods return a new string, they don’t modify the original.
- Transformation: use
upper(),lower(),capitalize(),title()to change capitalization;strip(),lstrip(),rstrip()to clean whitespace.- Searching: use
find()when unsure the substring exists (returns -1), useindex()when sure it exists and want an error if not.- split() and join() are the main pair for breaking apart and joining text;
join()is more efficient than+concatenation in loops.- Python 3.9+:
removeprefix()andremovesuffix()are safer than manual slicing for removing prefixes/suffixes.- Formatting: use f-strings for new code (Python 3.6+),
str.format()for stored templates, avoid%formatting.- The
stringmodule: constants likeascii_letters,digits,punctuationare useful for character validation;capwords()is more consistent thantitle();Templateis safe for templates from external input.