Swift
String Manipulation
Programming
Development
iOS

How to check what a String starts with prefix or ends with suffix in Swift

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

Introduction

Swift already gives you the two methods you usually want for this job: hasPrefix(_:) and hasSuffix(_:). They are simple, readable, and work correctly with Swift’s Unicode-aware String type. Most of the real nuance comes from case sensitivity and whether you need more advanced matching rules.

Check for a Prefix

Use hasPrefix(_:) when you want to know whether a string begins with a given substring:

swift
1let filename = "report.pdf"
2
3print(filename.hasPrefix("rep"))   // true
4print(filename.hasPrefix("Report")) // false

This returns a Bool and is case-sensitive by default.

That is usually exactly what you want for things like:

  • URL scheme checks
  • file extension preparation
  • command parsing
  • identifier prefixes

Check for a Suffix

Use hasSuffix(_:) for the ending part of the string:

swift
1let filename = "report.pdf"
2
3print(filename.hasSuffix(".pdf"))  // true
4print(filename.hasSuffix(".txt"))  // false

This is a very common pattern for checking file extensions or string markers.

Case-Insensitive Matching

Both methods are case-sensitive, so "Hello".hasPrefix("he") is false. If you need case-insensitive behavior, normalize both sides first:

swift
1let value = "HelloWorld"
2
3let starts = value.lowercased().hasPrefix("hello")
4let ends = value.lowercased().hasSuffix("world")
5
6print(starts) // true
7print(ends)   // true

This is fine for many practical cases, but remember that case conversion can be locale-sensitive in some domains. If exact linguistic behavior matters, use a comparison API with explicit options instead of assuming simple lowercase conversion is always perfect.

When You Need More Control

Sometimes you need rules beyond plain prefix or suffix matching, such as:

  • case-insensitive search without creating lowercase copies
  • locale-aware comparisons
  • ignoring diacritics
  • checking only a slice of the string

In those cases, use range(of:options:):

swift
1let value = "HelloWorld"
2
3let starts = value.range(
4    of: "hello",
5    options: [.anchored, .caseInsensitive]
6) != nil
7
8print(starts) // true

For a suffix-style check, combine .anchored and .backwards:

swift
1let ends = value.range(
2    of: "world",
3    options: [.anchored, .backwards, .caseInsensitive]
4) != nil
5
6print(ends) // true

This gives you more flexibility while still using Swift’s string APIs correctly.

Why Not Use Array-Like Indexing

Developers coming from other languages sometimes try to slice strings using integer indexes. Swift does not support that because strings are Unicode-aware and characters do not have uniform byte widths.

That is exactly why hasPrefix and hasSuffix are so helpful. They let you express intent directly without doing manual index arithmetic.

Practical Examples

Checking a URL scheme:

swift
1let url = "https://example.com"
2if url.hasPrefix("https://") {
3    print("Secure URL")
4}

Checking an image filename:

swift
1let imageName = "avatar.PNG"
2if imageName.lowercased().hasSuffix(".png") {
3    print("PNG image")
4}

These examples show why the built-in methods are usually preferable to more complicated manual string code.

Common Pitfalls

The biggest pitfall is forgetting that hasPrefix and hasSuffix are case-sensitive. That leads to a lot of confusing false negatives.

Another common issue is reaching for manual substring indexing when the built-in methods already express the intent clearly and safely.

People also sometimes forget Unicode behavior. Swift strings are not cheap byte arrays, so code patterns copied from other languages may be incorrect or awkward in Swift.

Finally, if the match rules are more complex than plain prefix or suffix logic, move to range(of:options:) instead of forcing everything through lowercase conversion and repeated temporary strings.

Summary

  • Use hasPrefix(_:) to check how a string starts.
  • Use hasSuffix(_:) to check how a string ends.
  • Both methods are case-sensitive by default.
  • For case-insensitive or more flexible matching, use range(of:options:).
  • Prefer Swift’s string APIs over manual index arithmetic.

Course illustration
Course illustration

All Rights Reserved.