Maha Arabic Text Processing Library

repository·main·Indexed 42 days ago

https://github.com/troboto/maha

A specialized Arabic text processing library for NLP applications, providing tools to clean and parse text, files, and directories with support for streaming. It includes capabilities for extracting semantic dimensions such as time, duration, distance, numerals, and ordinals, as well as utilities for converting numbers to Arabic text and optimizing regular expression matching via the Expression class.

Tokens
6.3K
Snippets
18
Records
26
Agent score
47%

What's inside Maha

  1. Overview of Maha text processing

    main

    Maha is an Arabic text processing library designed for NLP (Natural Language Processing) applications. It provides capabilities to clean and parse:

    • Text strings
    • Files
    • Folders

    The library supports both standard processing and streaming capabilities for handling large datasets.

  2. What is a custom dimension and how does it work?

    main

    A dimension is a rule that combines a set of special expressions (such as Value, MatchedValue, or FunctionValue) to define a regular expression paired with a corresponding value.

    The dimension lifecycle consists of two steps:

    1. The .parse() method of the rule is called on the input text, returning a list of ExpressionResult instances.
    2. Each body of the ExpressionResult is matched against the rule's special expressions. Once a match is found, the corresponding value is evaluated and returned.
  3. Handle match results with ExpressionResult

    main

    The ExpressionResult class provides a standardized interface for the results of a regular expression match. It ensures that every match result contains a consistent set of attributes, making it easier to process results from different expressions uniformly.

    Every ExpressionResult is guaranteed to have the following attributes:

    • start: The starting index of the match.
    • end: The ending index of the match.
    • value: The actual string content that was matched.
    • expression: The Expression object that produced this match.
  4. What are Maha Processors and when to use them

    main

    Processors extend the functionality of cleaners to work on files and folders. They allow for processing data in a streaming fashion, which is particularly useful for handling large files without loading them entirely into memory.

    Available processor types include:

    • TextProcessor: For processing simple text strings.
    • FileProcessor: For processing small files.
    • StreamTextProcessor: For processing streams of text.
    • StreamFileProcessor: For processing files in a streaming fashion.
  5. Use Maha cleaners to manipulate Arabic text

    main

    Maha provides a suite of cleaning functions categorized by their behavior. These functions use the regex library for efficiency and can be used with predefined constants or custom expressions.

    Available cleaner categories:

    • keep: Keeps only specific characters (e.g., arabic_letters, harakat).
    • remove: Removes specific characters (e.g., punctuations).
    • normalize: Converts similar characters into a common form (e.g., alef variations).
    • replace: Replaces specific characters with others.
    • contains: Checks for the presence of specific character sets.
    • num2text: Converts numeric digits into Arabic text representations.
    from maha.cleaners.functions import keep, remove, normalize, contains
    
    # Example: Keep only Arabic letters and Harakat
    keep("البسملة : ( بِسْمِ اللَّـهِ الرَّحْمَـٰنِ الرَّحِيمِ )", arabic_letters=True, harakat=True)
    
    # Example: Remove punctuations
    remove("البسملة : ( بِسْمِ اللَّـهِ الرَّحْمَـٰنِ الرَّحِيمِ )", punctuations=True)
    
    # Example: Normalize Alef variations
    normalize("أنا وأخي علي في المكتبةِ نَطلعُ على موضوع البرمجه", alef=True)
    
    # Example: Check if text contains Arabic letters
    contains("أنا وأخي علي في المكتبةِ نَدرسُ البرمجه", arabic_letters=True)
  6. How Maha parsers work

    main
    Maha parsers use highly optimized, compiled, and cached regular expressions called Rules (defined in maha.parsers.rules) to extract values from text. These rules are designed to handle the complexities of Arabic text extraction efficiently.
  7. Create a simple custom dimension using FunctionValue

    main

    You can create a simple rule by using FunctionValue. This allows you to define a pattern (using helper functions like spaced_patterns) and then pass a parsing function to evaluate the matched text into a specific value.

    In the example below, we create a rule to extract the number of books by matching a numeral followed by the word "كتاب" and then evaluating that numeral using parse_numeral.

    # Import the numeral rule.
    from maha.parsers.rules import RULE_NUMERAL
    # Import a helper function
    from maha.parsers.rules import spaced_patterns
    # Import the numeral parse function
    from maha.parsers.rules.numeral.rule import parse_numeral
    # Import the special expression, function value
    from maha.parsers.templates import FunctionValue
    
    # Define the rule: a number followed by a space and the word "كتاب".
    RULE_BOOK_NUMBER = FunctionValue(
        parse_numeral, spaced_patterns(RULE_NUMERAL, "كتاب"), pickle=False
    )
    
    # Use the rule to parse the text.
    sample_text = "في المكتبة مئة كتاب"
    result = list(RULE_BOOK_NUMBER.parse(sample_text))[0]
    print(result.value)  # Output: 100
    print(sample_text[result.start : result.end])  # Output: 'مئة كتاب'
  8. Create a multi-value custom dimension

    main

    For rules involving multiple distinct values (like durations), it is best to define a custom parse function that handles the logic for different matched patterns. You can then wrap this logic in a FunctionValue using a non_capturing_group to match various possible text representations.

    In this pattern, the custom parse function receives a match object. You can use .fullmatch() against predefined value rules (like ONE_SECOND or TWO_SECONDS) to return specific integers, or fall back to a general parser (like parse_numeral) for numeric patterns.

    from maha.rexy import non_capturing_group
    from maha.parsers.rules import spaced_patterns
    from maha.parsers.templates import FunctionValue
    from maha.parsers.rules.numeral.rule import parse_numeral
    # Import specific values for seconds
    from maha.parsers.rules.duration.values import ONE_SECOND, TWO_SECONDS, SEVERAL_SECONDS
    
    # Define a custom parse function for seconds
    def parse_seconds(match):
        matched_text = match.group(0)
        if TWO_SECONDS.fullmatch(matched_text):
            return 2
        if ONE_SECOND.fullmatch(matched_text):
            return 1
        # Fallback to numeral parsing for patterns like '100 ثانية'
        return parse_numeral(match)
    
    # Define the rule using a non-capturing group to handle multiple patterns
    RULE_SECONDS = FunctionValue(
        parse_seconds,
        non_capturing_group(
            # Pattern 1: number + seconds (e.g. 100 ثانية)
            spaced_patterns(RULE_NUMERAL, non_capturing_group(ONE_SECOND, SEVERAL_SECONDS)),
            # Pattern 2: specific words for two seconds
            TWO_SECONDS,
            # Pattern 3: specific words for one second
            ONE_SECOND,
        ),
        pickle=False,
    )
    
    # Usage
    sample_text = "تستغرق الف وعشرون ثانية للوصول"
    sample_text2 = "تصل في ثانيتين"
    
    print(list(RULE_SECONDS.parse(sample_text))[0].value)  # Output: 1020
    print(list(RULE_SECONDS.parse(sample_text2))[0].value) # Output: 2
  9. Use `processors` for large-scale text cleaning

    main
    While the standard cleaners.functions are efficient for individual strings, they are not optimized for massive datasets. If you need to clean a large volume of text or entire files, use the maha.processors module instead.