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
Use find() when you’re not sure the substring exists — it returns -1 when not found. Use index() 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.

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+. Use str.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. Use string.Template or str.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), use index() 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() and removesuffix() 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 string module: constants like ascii_letters, digits, punctuation are useful for character validation; capwords() is more consistent than title(); Template is safe for templates from external input.

← Previous: Articles & Resources   Next: IO →

About | Author | Content Scope | Editorial Policy | Privacy Policy | Disclaimer | Contact