3
\$\begingroup\$

Hello everyone!

In today's assignment I had to complete a rather unusual translator, take a look at my solution, tell me what I can do to make it better and show off yours!

Write a function that translates some text into New Polish and vice versa. Polish is translated into New Polish by taking the last letter of each word, moving it to the beginning of the word and adding ano at the beginning. Tom has a cat' becomes ['Anomto anosha anoa anotca'].

def new_polish_translator(input):
   
    result = ''

    content = input.replace(',', '').replace('.', '').replace('?', '').replace('-', '')
        
        #Dzieli na linie bez wchodzenia do nowej linii (\n)
    lines = [line.rstrip() for line in content.split("\n")]
    lines = [line for line in lines if len(line) > 0]

        #sprawdza czy nie jest przetlumaczony
    if all(line[-3::] == 'ano' for line in lines for word in line.split(' ')):
        result = ' '.join(lines)
        
        #sprawdza czy nie jest
    else:
        result = ' '.join('ano' + word[-1] + word[0:-1] for line in lines for word in line.split(' '))
        result = result.capitalize()
        
    return result


new_polish_translator("Tom has a cat")

result:

'Anomto anosha anoa anotca'

Have a great day!

\$\endgroup\$
1
  • 1
    \$\begingroup\$ Not super important, but I'll just note that this is basically just a variation of "Pig Latin". \$\endgroup\$ May 19, 2021 at 23:11

1 Answer 1

2
\$\begingroup\$

Your code is reasonable, but it does get tripped up if the text (input) contains multiple adjacent spaces or the cleaned text (content) ends up containing multiple adjacent spaces. It also could be simplified here and there. Some suggestions to consider: (1) parameterize the function so the user can control which punctuation characters to remove; (2) since the algorithm is fundamentally a word-based translation, it makes sense to convert the text to words early; (3) the check for already-translated text is not robust to capitalization; and (4) use the no-argument form of split() to avoid the bug noted above. Here's one way to make those changes:

def new_polish_translator(text, replace = ',.?-'):
    # Remove unwanted punctuation.
    for char in replace:
        text = text.replace(char, '')

    # Convert to words.
    words = text.split()

    # Translate, unless the text is already New Polish.
    prefix = 'ano'
    if all(w.lower().startswith(prefix) for w in words):
        np_words = words
    else:
        np_words = [prefix + w[-1] + w[0:-1] for w in words]

    # Return new text.
    return ' '.join(np_words).capitalize()

As you know already, this problem raises some tricky questions related to how the algorithm defines a "word". Simply splitting on whitespace and removing a few common punctuation markers will fail to handle a variety of human language inputs reasonably. There are other types of punctation (colon, semicolon, dash, and some weird ones), some words have internal punctuation (apostrophe), some words contain or even start with digits, some words convey additional meaning with capitalization, and some texts care about internal whitespace. Consider this specimen from Ogden Nash, and notice the details of spacing and punctuation lost during translation:

# English.

The camel has a single hump;
The dromedary, two;
Or else the other way around.
I'm never sure. Are you?

# New Polish.

Anoeth anolcame anosha anoa anoesingl ano;hump anoeth anoydromedar ano;two anoro anoeels anoeth anorothe anoywa anodaroun anomi' anorneve anoesur anoear anouyo

Is there a a practical way to make a translator that preserves more of those details? One approach is to use a basic tokenizing technique to decompose the input text into various tokens, some of which will be preserved as-is and some of which will be word-translated. These tokenizers are easy to build because they follow a simple pattern: try to match a sequence of regular expressions; stop on the first match; emit a Token; then re-enter the loop. In these situations, it helps to define some simple data-objects to represent search patterns and tokens. A sketch is shown below. It is purposely unfinished in the sense that it is missing some error handling (eg, checking that the patterns exhaust the text) and it doesn't try to preserve the original word capitalization. But those improvements are fairly easy to add if you are so inclined.

from collections import namedtuple
import re

Pattern = namedtuple('Pattern', 'kind regex')
Token = namedtuple('Token', 'kind text')

def new_polish_translator(text):
    # Define the search patterns.
    patterns = [
        Pattern('whitespace', re.compile('\s+')),
        Pattern('word', re.compile('[A-Za-z]+')),
        Pattern('other', re.compile('\S+')),
    ]

    # Translate only Token(kind=word). Preserve the rest.
    words = []
    for tok in tokenize(text, patterns):
        if tok.kind == 'word':
            w = tok.text
            words.append('ano' + w[-1] + w[0:-1])
        else:
            words.append(tok.text)

    # Return joined text.
    return ''.join(words)

def tokenize(text, patterns):
    pos = 0
    limit = len(text)
    while pos < limit:
        for p in patterns:
            m = p.regex.match(text, pos = pos)
            if m:
                txt = m.group(0)
                pos += len(txt)
                yield Token(p.kind, txt)
                break

Output:

anoeTh anolcame anosha anoa anoesingl anophum;
anoeTh anoydromedar, anootw;
anorO anoeels anoeth anorothe anoywa anodaroun.
anoI'm anorneve anoesur. anoeAr anouyo?
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.