Как сравнить две строки Python на равенство в регистронезависимом режиме?

PythonPythonBeginner
Практиковаться сейчас

💡 Этот учебник переведен с английского с помощью ИИ. Чтобы просмотреть оригинал, вы можете перейти на английский оригинал

Введение

При работе с текстовыми данными на Python вам часто приходится сравнивать строки, чтобы определить, содержат ли они одинаковую информацию, независимо от того, являются ли буквы заглавными или строчными. Это называется регистронезависимым сравнением строк.

В этом практическом занятии (LabEx) вы научитесь различным методам сравнения двух строк на Python на равенство, игнорируя различия в регистре. Вы рассмотрите базовое сравнение строк, различные техники регистронезависимого сравнения и узнаете, как применить эти навыки в реальных сценариях.

К концу этого практического занятия (LabEx) вы сможете уверенно реализовывать регистронезависимое сравнение строк в своих программах на Python, повысив свою способность эффективно обрабатывать текстовые данные.

Понимание сравнения строк в Python

Начнем с того, чтобы понять, как работает сравнение строк в Python и почему регистр имеет значение.

Стандартное сравнение строк

В Python, когда вы сравниваете две строки с помощью оператора равенства (==), по умолчанию сравнение является регистрозависимым. Это означает, что строки "Hello" и "hello" считаются разными.

Создадим новый файл Python, чтобы проверить это:

  1. В WebIDE нажмите на иконку "Explorer" в левой боковой панели.
  2. Нажмите на кнопку "New File" и назовите файл string_comparison.py.
  3. Добавьте следующий код в файл:
## Basic string comparison
string1 = "Python"
string2 = "python"

## Compare the strings
result = string1 == string2

## Print the result
print(f"Is '{string1}' equal to '{string2}'? {result}")
string comparison
  1. Сохраните файл, нажав Ctrl+S или выбрав "File" > "Save" в меню.
  2. Запустите скрипт, открыв терминал (Terminal > New Terminal) и введя:
python3 string_comparison.py

Вы должны увидеть следующий вывод:

Is 'Python' equal to 'python'? False

Вывод показывает False, потому что сравнение регистрозависимо, и "Python" с заглавной буквой 'P' не совпадает с "python" с маленькой буквой 'p'.

Почему регистронезависимое сравнение полезно

Регистронезависимое сравнение полезно во многих сценариях:

  • Валидация пользовательского ввода (пользователи могут вводить текст в любом регистре)
  • Поиск текста (поиск слов без учета регистра)
  • Обработка естественного языка (где регистр может различаться)
  • Работа с URL, адресами электронной почты или именами пользователей (которые могут быть регистронезависимы)

Изменим наш скрипт, чтобы добавить примеры, демонстрирующие, когда регистронезависимое сравнение полезно:

## Add these examples to string_comparison.py

## Example: User searching for content
user_search = "Python"
article_title = "Getting Started with python Programming"

## Case-sensitive comparison (might miss relevant content)
found_sensitive = user_search in article_title
print(f"Case-sensitive search found match: {found_sensitive}")

## What if we want to find matches regardless of case?
## We'll explore solutions in the next steps

Добавьте этот код в файл string_comparison.py и запустите его снова:

python3 string_comparison.py

Теперь вывод включает:

Case-sensitive search found match: False

Это показывает практическую проблему: пользователь, ищющий "Python", не найдет контент с заголовком "python Programming" с помощью стандартного регистрозависимого сравнения.

В следующем шаге мы научимся выполнять регистронезависимые сравнения, чтобы решить эту проблему.

Методы регистронезависимого сравнения строк

Теперь, когда вы понимаете, почему регистронезависимое сравнение важно, давайте научимся различным методам его выполнения в Python.

Метод 1: Использование lower() или upper()

Самый распространенный подход - это преобразовать обе строки в один и тот же регистр перед их сравнением. Для этого можно использовать методы lower() или upper().

Создадим новый файл, чтобы протестировать эти методы:

  1. В WebIDE создайте новый файл и назовите его case_insensitive.py.
  2. Добавьте следующий код:
## Case-insensitive comparison using lower()
string1 = "Python"
string2 = "python"

## Convert both strings to lowercase, then compare
result_lower = string1.lower() == string2.lower()
print(f"Using lower(): '{string1}' equals '{string2}'? {result_lower}")

## Convert both strings to uppercase, then compare
result_upper = string1.upper() == string2.upper()
print(f"Using upper(): '{string1}' equals '{string2}'? {result_upper}")
  1. Сохраните файл и запустите его с помощью команды:
python3 case_insensitive.py

Вы должны увидеть:

Using lower(): 'Python' equals 'python'? True
Using upper(): 'Python' equals 'python'? True

Оба метода дают одинаковый результат - они подтверждают, что строки равны, если игнорировать регистр.

Метод 2: Использование casefold()

Метод casefold() похож на lower(), но обеспечивает более агрессивное приведение к одному регистру, которое лучше работает для некоторых языков с специальными правилами сопоставления регистров.

Добавьте следующий код в файл case_insensitive.py:

## Case-insensitive comparison using casefold()
german_string1 = "Straße"  ## German word for "street"
german_string2 = "STRASSE" ## Uppercase version (note: ß becomes SS when uppercased)

## Using lower()
result_german_lower = german_string1.lower() == german_string2.lower()
print(f"Using lower() with '{german_string1}' and '{german_string2}': {result_german_lower}")

## Using casefold()
result_german_casefold = german_string1.casefold() == german_string2.casefold()
print(f"Using casefold() with '{german_string1}' and '{german_string2}': {result_german_casefold}")

Запустите скрипт еще раз:

python3 case_insensitive.py

Вы увидите:

Using lower() with 'Straße' and 'STRASSE': False
Using casefold() with 'Straße' and 'STRASSE': True

Это показывает, что casefold() лучше обрабатывает специальные сопоставления символов, чем lower() в некоторых языках.

Метод 3: Использование регулярных выражений

Для более сложных сценариев можно использовать регулярные выражения с модулем re и флагом IGNORECASE:

Добавьте следующий код в файл case_insensitive.py:

## Case-insensitive comparison using regular expressions
import re

text = "Python is a great programming language."
pattern1 = "python"

## Check if 'python' exists in the text (case-insensitive)
match = re.search(pattern1, text, re.IGNORECASE)
print(f"Found '{pattern1}' in text? {match is not None}")

## Case-insensitive equality check with regex
def regex_equal_ignore_case(str1, str2):
    return bool(re.match(f"^{re.escape(str1)}$", str2, re.IGNORECASE))

## Test the function
result_regex = regex_equal_ignore_case("Python", "python")
print(f"Using regex: 'Python' equals 'python'? {result_regex}")

Запустите скрипт еще раз:

python3 case_insensitive.py

Вы должны увидеть:

Found 'python' in text? True
Using regex: 'Python' equals 'python'? True

Сравнение методов

Подведем итог изученным методам:

  • lower()/upper(): Простой и часто используемый, работает для большинства английского текста
  • casefold(): Лучше подходит для международного текста с специальными правилами сопоставления регистров
  • Регулярные выражения с re.IGNORECASE: Мощный инструмент для сопоставления шаблонов и сложных случаев

Добавьте этот итог в файл case_insensitive.py в виде комментария для справки:

## Summary of case-insensitive comparison methods:
## 1. string1.lower() == string2.lower() - Simple, works for basic cases
## 2. string1.casefold() == string2.casefold() - Better for international text
## 3. re.match(pattern, string, re.IGNORECASE) - For pattern matching

Теперь, когда вы знаете различные методы, давайте применим эти техники к практическим сценариям на следующем шаге.

Создание регистронезависимой функции поиска

Теперь, когда вы узнали различные методы регистронезависимого сравнения, давайте создадим практическую функцию поиска, которая может находить слова в тексте без учета регистра.

Создание функции поиска

  1. В WebIDE создайте новый файл и назовите его search_function.py.
  2. Добавьте следующий код для реализации простой регистронезависимой функции поиска:
def search_text(query, text):
    """
    Search for a query in text, ignoring case.
    Returns a list of all matching positions.
    """
    ## Convert both to lowercase for case-insensitive comparison
    query_lower = query.lower()
    text_lower = text.lower()

    found_positions = []
    position = 0

    ## Find all occurrences
    while position < len(text_lower):
        position = text_lower.find(query_lower, position)
        if position == -1:  ## No more matches
            break
        found_positions.append(position)
        position += 1  ## Move to the next character

    return found_positions

## Example text
sample_text = """
Python is a programming language that lets you work quickly and integrate systems effectively.
python is easy to learn, powerful, and versatile.
Many developers love PYTHON for its simplicity and readability.
"""

## Test search
search_query = "python"
results = search_text(search_query, sample_text)

## Display results
if results:
    print(f"Found '{search_query}' at {len(results)} positions: {results}")

    ## Show each match in context
    print("\nMatches in context:")
    for pos in results:
        ## Get some context around the match (10 characters before and after)
        start = max(0, pos - 10)
        end = min(len(sample_text), pos + len(search_query) + 10)
        context = sample_text[start:end]

        ## Highlight the match by showing the original case from the text
        match_original_case = sample_text[pos:pos+len(search_query)]
        print(f"...{context.replace(match_original_case, f'[{match_original_case}]')}...")
else:
    print(f"No matches found for '{search_query}'")
  1. Сохраните файл и запустите его с помощью команды:
python3 search_function.py

Вы должны увидеть вывод, похожий на следующий:

Found 'python' at 3 positions: [1, 67, 132]

Matches in context:
...[Python] is a pro...
...ctively.
[python] is easy ...
...ers love [PYTHON] for its ...

Это показывает, что наша функция нашла "Python" в трех местах, независимо от того, было ли оно написано как "Python", "python" или "PYTHON". Функция также показывает каждое совпадение в его исходном контексте, сохраняя исходный регистр.

Улучшение функции поиска

Давайте улучшим нашу функцию, чтобы сделать ее более полезной, добавив возможность подсчитывать слова и обрабатывать совпадения целых слов:

Добавьте следующий код в файл search_function.py:

def count_word_occurrences(word, text, whole_word=False):
    """
    Count occurrences of a word in text, ignoring case.
    If whole_word=True, only count complete word matches.
    """
    word_lower = word.lower()
    text_lower = text.lower()

    if whole_word:
        ## Use word boundaries to match whole words only
        import re
        pattern = r'\b' + re.escape(word_lower) + r'\b'
        matches = re.findall(pattern, text_lower)
        return len(matches)
    else:
        ## Simple substring counting
        return text_lower.count(word_lower)

## Test the enhanced function
test_text = """
Python is great. I love python programming.
This python-script demonstrates case-insensitive searching.
The word "python" appears multiple times as a whole word and as part of other words.
"""

## Count all occurrences (including within words)
count_all = count_word_occurrences("python", test_text)
print(f"Total occurrences of 'python' (including within words): {count_all}")

## Count only whole word occurrences
count_whole = count_word_occurrences("python", test_text, whole_word=True)
print(f"Whole word occurrences of 'python': {count_whole}")

Запустите скрипт еще раз:

python3 search_function.py

Теперь вы должны увидеть дополнительный вывод:

Total occurrences of 'python' (including within words): 4
Whole word occurrences of 'python': 3

Это показывает, что "python" встречается в тексте 4 раза в общей сложности, но только 3 раза как целое слово (одно вхождение в "python-script" не является совпадением целого слова).

Тестирование различных сценариев

Давайте добавим еще один тест, чтобы показать, как наша функция обрабатывает разные типы текста:

## Add more test cases
test_cases = [
    ("Python programming is fun", "python", "Simple sentence with one occurrence"),
    ("Python, python, PYTHON!", "python", "Multiple occurrences with different cases"),
    ("No matches here", "python", "No matches"),
    ("Python-script and PythonProgram contain python", "python", "Mixed word boundaries")
]

print("\nTesting different scenarios:")
for text, search_word, description in test_cases:
    whole_matches = count_word_occurrences(search_word, text, whole_word=True)
    all_matches = count_word_occurrences(search_word, text)

    print(f"\nScenario: {description}")
    print(f"Text: '{text}'")
    print(f"  - Whole word matches: {whole_matches}")
    print(f"  - All matches: {all_matches}")

Добавьте этот код и запустите скрипт еще раз:

python3 search_function.py

Вы увидите подробный разбор того, как функция обрабатывает различные сценарии текста:

Testing different scenarios:

Scenario: Simple sentence with one occurrence
Text: 'Python programming is fun'
  - Whole word matches: 1
  - All matches: 1

Scenario: Multiple occurrences with different cases
Text: 'Python, python, PYTHON!'
  - Whole word matches: 3
  - All matches: 3

Scenario: No matches
Text: 'No matches here'
  - Whole word matches: 0
  - All matches: 0

Scenario: Mixed word boundaries
Text: 'Python-script and PythonProgram contain python'
  - Whole word matches: 1
  - All matches: 3

Это демонстрирует, как регистронезависимое сравнение может быть использовано в реальной функции поиска с возможностью обработки различных требований к поиску.

На следующем шаге мы применим эти техники для создания практического приложения для валидации пользовательского ввода.

Создание приложения для валидации пользовательского ввода

На этом последнем шаге мы создадим практическое приложение, которое использует регистронезависимое сравнение строк для валидации пользовательского ввода. Это распространенный запрос в многих реальных приложениях.

Простой валидатор команд

  1. В WebIDE создайте новый файл и назовите его command_validator.py.
  2. Добавьте следующий код для реализации простого валидатора команд:
def validate_command(user_input, valid_commands):
    """
    Validate if the user input matches any of the valid commands,
    ignoring case differences.

    Returns the standardized command if valid, None otherwise.
    """
    ## Convert user input to lowercase for comparison
    user_input_lower = user_input.strip().lower()

    for cmd in valid_commands:
        if user_input_lower == cmd.lower():
            ## Return the standard casing of the command
            return cmd

    ## No match found
    return None

## List of valid commands with standard casing
VALID_COMMANDS = [
    "Help",
    "Exit",
    "List",
    "Save",
    "Delete"
]

## Test with various inputs
test_inputs = [
    "help",      ## lowercase
    "EXIT",      ## uppercase
    "List",      ## correct case
    "  save  ",  ## with extra spaces
    "delete",    ## lowercase
    "unknown",   ## invalid command
    "hlep"       ## typo
]

print("Command Validator Test:")
print("=" * 30)
print(f"Valid commands: {VALID_COMMANDS}")
print("=" * 30)

for cmd in test_inputs:
    result = validate_command(cmd, VALID_COMMANDS)
    if result:
        print(f"'{cmd}' is valid ✓ (standardized to '{result}')")
    else:
        print(f"'{cmd}' is invalid ✗")
  1. Сохраните файл и запустите его с помощью команды:
python3 command_validator.py

Вы должны увидеть вывод, похожий на следующий:

Command Validator Test:
==============================
Valid commands: ['Help', 'Exit', 'List', 'Save', 'Delete']
==============================
'help' is valid ✓ (standardized to 'Help')
'EXIT' is valid ✓ (standardized to 'Exit')
'List' is valid ✓ (standardized to 'List')
'  save  ' is valid ✓ (standardized to 'Save')
'delete' is valid ✓ (standardized to 'Delete')
'unknown' is invalid ✗
'hlep' is invalid ✗

Это показывает, как регистронезависимое сравнение можно использовать для валидации пользовательских команд, сохраняя при этом стандартизированный формат вывода.

Интерактивный обработчик команд

Теперь давайте создадим интерактивную версию, где пользователи могут вводить команды напрямую:

  1. Создайте новый файл с именем interactive_commands.py.
  2. Добавьте следующий код:
## Interactive command processor using case-insensitive validation

## Valid commands with descriptions
COMMANDS = {
    "Help": "Display available commands",
    "List": "List all items",
    "Add": "Add a new item",
    "Delete": "Delete an item",
    "Exit": "Exit the program"
}

def process_command(command):
    """Process a command entered by the user."""
    ## Normalize command (remove extra spaces, convert to standard case)
    normalized = None

    ## Check if command matches any valid command (case-insensitive)
    for valid_cmd in COMMANDS:
        if command.strip().lower() == valid_cmd.lower():
            normalized = valid_cmd
            break

    ## Process the command
    if normalized == "Help":
        print("\nAvailable commands:")
        for cmd, desc in COMMANDS.items():
            print(f"  {cmd} - {desc}")

    elif normalized == "List":
        print("\nListing all items:")
        print("  (This is where your actual items would be displayed)")

    elif normalized == "Add":
        print("\nAdding a new item:")
        print("  (In a real application, you would prompt for item details here)")

    elif normalized == "Delete":
        print("\nDeleting an item:")
        print("  (In a real application, you would prompt for which item to delete)")

    elif normalized == "Exit":
        print("\nExiting program. Goodbye!")
        return False

    else:
        print(f"\nUnknown command: '{command}'")
        print("Type 'help' to see available commands")

    return True

def main():
    """Main program loop."""
    print("=== Simple Command Processor ===")
    print("Type 'help' to see available commands.")
    print("Commands are case-insensitive, so 'help', 'HELP', and 'Help' all work the same.")

    running = True
    while running:
        user_input = input("\nEnter a command: ")
        running = process_command(user_input)

if __name__ == "__main__":
    main()
  1. Сохраните файл и запустите его:
python3 interactive_commands.py

Вы увидите интерактивный запрос:

=== Simple Command Processor ===
Type 'help' to see available commands.
Commands are case-insensitive, so 'help', 'HELP', and 'Help' all work the same.

Enter a command:
  1. Попробуйте ввести различные команды с разным регистром:
    • help (строчные буквы)
    • LIST (заглавные буквы)
    • Add (смешанный регистр)
    • exit (для выхода из программы)

Программа будет корректно обрабатывать каждую команду, независимо от используемого регистра.

Обзор методов валидации ввода

Давайте создадим еще один файл, чтобы обобщить различные методы, которые мы узнали для регистронезависимой валидации ввода:

  1. Создайте файл с именем validation_techniques.py.
  2. Добавьте следующий код:
"""
Summary of Case-Insensitive Input Validation Techniques
"""

## Example data
valid_options = ["Yes", "No", "Maybe"]
user_responses = ["yes", "NO", "mAyBe", "unknown"]

print("Case-Insensitive Input Validation Techniques\n")

## Technique 1: Simple lowercase comparison
print("Technique 1: Simple lowercase comparison")
for response in user_responses:
    is_valid = response.lower() in [opt.lower() for opt in valid_options]
    print(f"  Is '{response}' valid? {is_valid}")

## Technique 2: Using a validation function
print("\nTechnique 2: Using a validation function")
def validate_input(user_input, valid_options):
    return any(user_input.lower() == opt.lower() for opt in valid_options)

for response in user_responses:
    is_valid = validate_input(response, valid_options)
    print(f"  Is '{response}' valid? {is_valid}")

## Technique 3: Mapping to standardized values
print("\nTechnique 3: Mapping to standardized values")
def standardize_input(user_input, valid_options):
    for opt in valid_options:
        if user_input.lower() == opt.lower():
            return opt
    return None

for response in user_responses:
    standard_form = standardize_input(response, valid_options)
    if standard_form:
        print(f"  '{response}' is valid and maps to '{standard_form}'")
    else:
        print(f"  '{response}' is invalid")

## Technique 4: Using dictionaries for case-insensitive lookup
print("\nTechnique 4: Using dictionaries for case-insensitive lookup")
## Create a case-insensitive lookup dictionary
lookup_dict = {opt.lower(): opt for opt in valid_options}

for response in user_responses:
    if response.lower() in lookup_dict:
        standard_form = lookup_dict[response.lower()]
        print(f"  '{response}' is valid and maps to '{standard_form}'")
    else:
        print(f"  '{response}' is invalid")
  1. Сохраните файл и запустите его:
python3 validation_techniques.py

Вы увидите сравнение различных методов валидации:

Case-Insensitive Input Validation Techniques

Technique 1: Simple lowercase comparison
  Is 'yes' valid? True
  Is 'NO' valid? True
  Is 'mAyBe' valid? True
  Is 'unknown' valid? False

Technique 2: Using a validation function
  Is 'yes' valid? True
  Is 'NO' valid? True
  Is 'mAyBe' valid? True
  Is 'unknown' valid? False

Technique 3: Mapping to standardized values
  'yes' is valid and maps to 'Yes'
  'NO' is valid and maps to 'No'
  'mAyBe' is valid and maps to 'Maybe'
  'unknown' is invalid

Technique 4: Using dictionaries for case-insensitive lookup
  'yes' is valid and maps to 'Yes'
  'NO' is valid and maps to 'No'
  'mAyBe' is valid and maps to 'Maybe'
  'unknown' is invalid

Этот обзор показывает различные подходы к реализации регистронезависимой валидации, предоставляя вам возможность выбрать подходящий для ваших конкретных потребностей.

Завершив этот шаг, вы узнали, как применить регистронезависимое сравнение строк в практическом сценарии валидации пользовательского ввода.

Резюме

Поздравляем вас с успешным завершением этого практического занятия (лабораторной работы) по регистронезависимому сравнению строк в Python. Вот то, что вы узнали:

  1. Основы сравнения строк в Python и почему регистр имеет значение.

  2. Несколько методов для выполнения регистронезависимого сравнения строк:

    • Использование методов lower() и upper().
    • Использование метода casefold() для международного текста.
    • Использование регулярных выражений с флагом re.IGNORECASE.
  3. Как создавать практические приложения с использованием регистронезависимого сравнения:

    • Создание функции поиска, которая находит текст независимо от регистра.
    • Реализация валидации пользовательского ввода, которая работает с любым регистром букв.
    • Обработка команд в регистронезависимом режиме.

Эти навыки ценны в многих реальных программировании задач, начиная от создания пользовательских интерфейсов и заканчивая обработкой текстовых данных. Регистронезависимое сравнение строк - это фундаментальная техника, которая улучшает пользовательский опыт и делает ваши приложения более надежными и удобными в использовании.

По мере того, как вы продолжите изучать Python, помните, что эти методы можно комбинировать с другими методами обработки строк для решения все более сложных задач обработки текста.