String Operations: Joining, Repeating, Searching and Comparing

Concatenation, repetition, membership testing, comparison and iteration - the operations that work on strings because a string is a sequence.

Concatenation

first = "Meera"
last = "Nair"

print(first + " " + last)        # Meera Nair
print(first "Nair")              # SyntaxError in this form
print("Meera" "Nair")            # MeeraNair - adjacent LITERALS join automatically

Adjacent string literals are joined by the compiler. That is useful for splitting a long literal across lines, and it is a trap when a comma is left out of a list:

message = (
    "This is a long message that "
    "continues on the next line "
    "without any + signs."
)

names = ["Meera", "Arun" "Sara"]     # only TWO items: the last two joined
print(len(names))                    # 2

Concatenation in a loop is a mistake

parts = ["a", "b", "c", "d"]

# Slow: builds a brand new string on every iteration.
result = ""
for part in parts:
    result += part

# Fast and idiomatic: one allocation.
result = "".join(parts)

Because strings are immutable, += cannot extend in place; it copies everything built so far. For four items that is irrelevant, for forty thousand it is the difference between instant and unusable.

Repetition

print("-" * 30)             # a separator line
print("ab" * 3)             # ababab
print("=" * 0)              # empty string, no error
print("x" * -2)             # empty string too

print("Menu".center(30, "-"))    # ------------Menu--------------

Membership

text = "Python programming"

print("gram" in text)          # True
print("Gram" in text)          # False - case sensitive
print("gram" not in text)      # False

# Case insensitive test
print("gram" in text.lower())  # True

in on a string is a substring test, not a character test. "th" in "Python" is True even though "th" is two characters.

Comparison

print("apple" == "apple")      # True
print("apple" < "banana")      # True
print("Apple" < "apple")       # True  - uppercase sorts first
print("abc" < "abd")           # True  - first differing character decides
print("abc" < "abcd")          # True  - a prefix sorts before the longer string

Comparison walks the strings character by character and compares Unicode code points. Because every uppercase ASCII letter has a lower code point than every lowercase one, "Z" < "a" is True. Sort case insensitively on purpose when that matters:

names = ["banana", "Apple", "cherry"]

print(sorted(names))                    # ['Apple', 'banana', 'cherry']
print(sorted(names, key=str.lower))     # ['Apple', 'banana', 'cherry'] by word
print(sorted(names, key=str.casefold))  # the most robust form for non English text

Iteration

text = "Python"

for character in text:
    print(character, end="|")
print()                                   # P|y|t|h|o|n|

for index, character in enumerate(text, start=1):
    print(index, character)

vowels = sum(1 for ch in text.lower() if ch in "aeiou")
print(vowels)                             # 1

Iterating over words and lines

sentence = "the quick brown fox"

for word in sentence.split():
    print(word.capitalize())

document = "line one\nline two\nline three"
for line in document.splitlines():
    print(">", line)

Useful built ins that work on strings

text = "Python"

print(len(text))               # 6
print(min(text), max(text))    # P y   - by code point
print(sorted(text))            # ['P', 'h', 'n', 'o', 't', 'y']
print("".join(sorted(text)))   # Phnoty
print(list(reversed(text)))    # ['n', 'o', 'h', 't', 'y', 'P']
print("".join(reversed(text))) # nohtyP

A practical example

def is_palindrome(text):
    cleaned = "".join(ch.lower() for ch in text if ch.isalnum())
    return cleaned == cleaned[::-1]


print(is_palindrome("A man, a plan, a canal: Panama"))    # True
print(is_palindrome("Python"))                            # False


def word_frequency(sentence):
    counts = {}
    for word in sentence.lower().split():
        word = word.strip(".,!?;:")
        counts[word] = counts.get(word, 0) + 1
    return counts


print(word_frequency("the cat and the hat and the bat"))

Common mistakes

  • Building a string with += inside a large loop.
  • Forgetting a comma in a list of string literals, so two items silently merge.
  • Comparing strings without normalising case when case is not meaningful.
  • Using + to mix a string and a number. "Total: " + 5 is a TypeError; use an f-string.
  • Assuming sorted(text) returns a string. It returns a list of characters.
  • Assuming "a" in text checks characters only. It checks substrings of any length.

Best practices

  • Use "".join(parts) to assemble strings from many pieces.
  • Use f-strings to mix text and values rather than concatenation.
  • Normalise with .casefold() before comparing text that came from users.
  • Use bracket continuation for long literals rather than backslashes or +.

Practice

  1. Explain why ["a", "b" "c"] has two elements and how to spot the bug in review.
  2. Write a function that counts vowels and consonants in a sentence.
  3. Compare the running time of += concatenation and join for 100 000 pieces, and describe the result.
  4. Sort a list of names case insensitively without changing the stored capitalisation.
  5. Write a palindrome check that ignores punctuation, spacing and case.

Conclusion

Strings support the sequence operations - join with +, repeat with *, search with in, compare by code point, iterate by character. The only rule that changes how you write code is immutability, which is why join exists and why you should reach for it.

Written by Lorens Mishra

Default administrator account created by the installer.

Continue reading

All Python notes →

Discussion

0 comments
Sign in to join the discussion.

No comments yet. Be the first to say something.