The Weekly Challenge 365

A-to-Z Number Crunch & Word Police Patrol!

Original Challenge Link

Task 1: Alphabet Index Digit Sum

"From A to 26, Then Add It All Up!"

This week's first task involves converting letters to numbers and performing digit sum operations. Given a string of lowercase letters and an integer K, we convert each letter to its alphabet position (a=1, b=2, ..., z=26), concatenate them to form an integer, then compute the sum of its digits repeatedly K times.

The Strategy: First, we convert each character to its numeric position. Then we sum the digits of the resulting number. For multiple iterations (K > 1), we repeat the digit-sum process until we've applied it K times.
Perl Implementation
sub alphabet_index_digit_sum {
    my ($str, $k) = @_;
    
    die "Error: str must be defined\n" unless defined $str;
    die "Error: k must be a positive integer\n" unless defined $k && $k =~ /^\d+$/;
    
    my $numbers = '';
    for my $char (split //, $str) {
        my $ord = ord($char) - ord('a') + 1;
        $numbers .= $ord;
    }
    
    my $sum = 0;
    for my $digit (split //, $numbers) {
        $sum += $digit;
    }
    
    for my $i (2 .. $k) {
        my $new_sum = 0;
        for my $digit (split //, $sum) {
            $new_sum += $digit;
        }
        $sum = $new_sum;
    }
    
    return $sum;
}
Python Implementation
def alphabet_index_digit_sum(text: str, k: int) -> int:
    """
    Convert string to numbers, sum digits K times.
    
    Args:
        text: String of lowercase English letters.
        k: Number of times to sum digits.
        
    Returns:
        The final digit sum after K iterations.
        
    Raises:
        ValueError: If text is empty or k is not positive.
    """
    if not text:
        raise ValueError("text must not be empty")
    if k < 1:
        raise ValueError("k must be a positive integer")
    
    numbers: str = ""
    for char in text:
        if not ('a' <= char <= 'z'):
            raise ValueError(f"Invalid character: {char}")
        num = ord(char) - ord('a') + 1
        numbers += str(num)
    
    digit_sum = sum(int(d) for d in numbers)
    
    for _ in range(2, k + 1):
        digit_sum = sum(int(d) for d in str(digit_sum))
    
    return digit_sum

Task 2: Valid Token Counter

"The Word Police: Punctuation and Hyphen Patrol!"

The second task involves parsing a sentence and counting valid tokens. A token is valid if it contains no digits, has at most one hyphen surrounded by lowercase letters, and has at most one punctuation mark (!, ., ,) appearing only at the end.

The Strategy: We split the sentence into tokens and validate each one. For each token, we check: no digits, correct punctuation placement, and proper hyphen usage. The key is handling the interaction between punctuation and hyphens correctly.
Perl Implementation
sub valid_token_counter {
    my ($sentence) = @_;
    
    die "Error: sentence must be defined\n" unless defined $sentence;
    
    my @tokens = split /\s+/, $sentence;
    my $valid_count = 0;
    
    for my $token (@tokens) {
        $valid_count++ if _is_valid_token($token);
    }
    
    return $valid_count;
}

sub _is_valid_token {
    my ($token) = @_;
    
    return 0 if $token =~ /\d/;
    
    my $punct_count = () = $token =~ /[!. ,]/g;
    return 0 if $punct_count > 1;
    
    my $punct = '';
    if ($token =~ /([!. ,])$/) {
        $punct = $1;
    }
    return 0 if $punct && $token !~ /[!. ,]$/;
    
    my $base = $token;
    $base =~ s/[!. ,]$// if $punct;
    
    my $hyphen_count = () = $base =~ /-/g;
    return 0 if $hyphen_count > 1;
    
    if ($hyphen_count == 1) {
        my @parts = split /-/, $base;
        return 0 if scalar @parts != 2;
        return 0 unless $parts[0] =~ /^[a-z]+$/ && $parts[1] =~ /^[a-z]+$/;
        my $no_hyphen = $base;
        $no_hyphen =~ s/-//g;
        return 0 if $no_hyphen =~ /[^a-z]/;
    } else {
        return 0 if $base =~ /[^a-z]/;
    }
    
    return 1;
}
Python Implementation
def valid_token_counter(sentence: str) -> int:
    """
    Count valid tokens in a sentence.
    
    Args:
        sentence: A string with space-separated tokens.
        
    Returns:
        Number of valid tokens.
        
    Raises:
        ValueError: If sentence is None.
    """
    if sentence is None:
        raise ValueError("sentence must not be None")
    
    tokens: List[str] = sentence.split()
    valid_count: int = 0
    
    for token in tokens:
        if _is_valid_token(token):
            valid_count += 1
    
    return valid_count


def _is_valid_token(token: str) -> bool:
    """
    Check if a single token is valid.
    
    A token is valid if:
        - Contains no digits
        - Has at most one hyphen, surrounded by lowercase letters
        - Has at most one punctuation mark (!, ., ,) at the end only
    """
    if re.search(r'\d', token):
        return False
    
    punctuation_marks = re.findall(r'[!. ,]', token)
    if len(punctuation_marks) > 1:
        return False
    
    punct = ''
    if re.search(r'[!. ,]$', token):
        punct = re.search(r'([!. ,])$', token).group(1)
    
    if punct and not re.search(r'[!. ,]$', token):
        return False
    
    base = token
    if punct:
        base = base[:-1]
    
    hyphens = base.count('-')
    if hyphens > 1:
        return False
    
    if hyphens == 1:
        parts = base.split('-')
        if len(parts) != 2:
            return False
        if not (re.match(r'^[a-z]+$', parts[0]) and re.match(r'^[a-z]+$', parts[1])):
            return False
        no_hyphen = base.replace('-', '')
        if re.search(r'[^a-z]', no_hyphen):
            return False
    else:
        if re.search(r'[^a-z]', base):
            return False
    
    return True