Python String Characteristics Lab

Lab: The “Immutable” Log Fixer

Scenario: You have received a server log where the server name was recorded incorrectly as "server-production". Due to a policy change, all servers must start with "SRV-". Since you cannot change the string in place, you must reconstruct it.

Task:

  1. Check if the string starts with “server”.
  2. Create a new string that replaces “server” with “SRV”.
  3. Verify the new string is actually a new object in memory.
# Lab Code

# 1. Old String
old_log = "server-production-01"
print(f"Original: {old_log} | ID: {id(old_log)}")

# 2. Transformation (Since we can't do old_log[0:6] = "SRV")
# We use slicing to keep everything AFTER index 6 ("-production-01")
remaining_part = old_log[6:] 

# Construct New String
new_log = "SRV" + remaining_part

# 3. Verification
print(f"Fixed:    {new_log} | ID: {id(new_log)}")

# Logic Check
if id(old_log) != id(new_log):
    print("Success: A new immutable string object was created.")
else:
    print("Error: IDs match.")

Lab 1: Visualizing Immutability (Memory Lab)

Task: Prove that modifying a string changes its memory location.

# Lab 1: The Identity Check
user_role = "admin"
print(f"Original Role: {user_role} | Memory Address: {id(user_role)}")

# Attempt to 'modify' (concatenation)
user_role = user_role + "_sys"
print(f"New Role:      {user_role} | Memory Address: {id(user_role)}")

# Observation: The memory addresses are totally different. 
# Proof: The original "admin" string was NOT changed; a new "admin_sys" was created.

Lab 2: Iteration for Security (Password Strength)

Task: Use the Iterable nature of strings to count digits in a password.

# Lab 2: The Strength Checker
password = "SecurePass123!"
digit_count = 0

# Iterating through the string character by character
for char in password:
    # Check if the character is a number
    if char.isdigit():
        digit_count += 1

print(f"Password '{password}' contains {digit_count} numbers.")
# Output: Password 'SecurePass123!' contains 3 numbers.

Lab 3: Ordered Slicing (Log Extraction)

Task: Use the Ordered nature to extract specific data from a structured string.

# Lab 3: The Order Extractor
# Standard Format: [Date] [Level] Message
log_entry = "[2026-01-28] [ERROR] DB Connection Failed"

# Because strings are ordered, we know exactly where the Date is relative to brackets
date_part = log_entry[1:11] 
print(f"Date of Incident: {date_part}")
# Output: 2026-01-28

Lab 1: The “Secret Key” Masker (Immutability & Ordering)

Concept: Since strings are Immutable, you cannot just overwrite the middle characters of a password to hide them. You must use Slicing (Order) to cut the head and tail, and create a new string with stars in the middle.

Scenario: You are building a logging system. When an API Key is printed to the logs, it must be masked so that only the first 4 and last 4 characters are visible.

Input: API_KEY = "SK_live_51Mz9AaT7bCq8Zp2"

Task:

  1. Extract the first 4 characters.
  2. Extract the last 4 characters.
  3. Calculate how many hidden characters are in the middle.
  4. Create a new masked string.
# Lab 1 Solution

api_key = "SK_live_51Mz9AaT7bCq8Zp2"

# 1. Slice the Start (Indices 0 to 3)
prefix = api_key[0:4] 

# 2. Slice the End (Last 4 characters)
suffix = api_key[-4:]

# 3. Calculate masking length
# Total length - (length of prefix + length of suffix)
mask_length = len(api_key) - (len(prefix) + len(suffix))

# 4. Construct the NEW string (Concatenation)
masked_key = prefix + ("*" * mask_length) + suffix

print(f"Original: {api_key}")
print(f"Masked:   {masked_key}")

# Verification of Immutability:
# api_key is still the same. 'masked_key' is a new object.
print(f"Original is untouched: {api_key}")

Lab 2: The Permission Analyzer (Iterable)

Concept: Strings are Iterable. You can loop through them to check every single character.

Scenario: In Linux, file permissions are often shown as strings like rwxr-xr-x (Read, Write, Execute). You need to write a script that iterates through this string and raises a “Security Alert” if the Write (‘w’) permission is found more than once (meaning it’s too open).

Input: permissions = "rwxrwxrwx" (777 – Very Dangerous!)

Task:

  1. Loop through the string character by character.
  2. Count how many times 'w' appears.
  3. If count > 1, print a red alert.
# Lab 2 Solution

permissions = "rwxrwxrwx"
write_count = 0

# 1. Iterate through the string
for char in permissions:
    # 2. Check condition
    if char == 'w':
        write_count = write_count + 1

# 3. Decision Logic
print(f"Analyzing permissions: {permissions}")

if write_count > 1:
    print(f"SECURITY ALERT: Write permission found {write_count} times! Too dangerous.")
else:
    print("Permissions look safe.")

Lab 3: The Version Extractor (Ordered)

Concept: Strings are Ordered. We rely on specific positions (indexes) to extract meaningful data.

Scenario: You have a list of backup files named backup_2026_v1.tar.gz. You need to extract just the Year (2026) to organize them into folders. You know the format is always backup_YEAR_....

Task: Use slicing with specific indices to extract the year.

# Lab 3 Solution

filename = "backup_2026_v1.tar.gz"

# We know the format:
# b a c k u p _ 2 0 2 6 ...
# 0 1 2 3 4 5 6 7 8 9 10

# The year starts at index 7 and ends at index 11 (exclusive)
year = filename[7:11]

print(f"Processing File: {filename}")
print(f"Extracted Year: {year}")

# Advanced Architect Tip: 
# If the filename length changes, slicing by hard numbers is risky. 
# Better to use .split('_') if the separator is consistent.
parts = filename.split('_') # ['backup', '2026', 'v1.tar.gz']
print(f"Safer Extraction: {parts[1]}")

Lab 4: The “Reverse” Encryption (Ordered)

Concept: Python’s unique slicing capability [::-1] allows you to reverse the Order of a string instantly.

Scenario: You need to send a simple obfuscated message over a network so it isn’t readable by a casual glance. You decide to reverse the string.

Task:

  1. Take a message string.
  2. Create a reversed version.
  3. Reverse it back to prove it works.
# Lab 4 Solution

message = "DevSecOps"

# 1. Reverse the string using negative step slicing
# Syntax: [start : end : step]
# Step -1 means "walk backwards"
encrypted = message[::-1]

print(f"Original:  {message}")
print(f"Encrypted: {encrypted}")

# 2. Decrypt (Reverse the reversed string)
decrypted = encrypted[::-1]

print(f"Decrypted: {decrypted}")

# Validation
if message == decrypted:
    print("Integrity Check Passed.")

Leave a Comment

Your email address will not be published. Required fields are marked *

Scroll to Top