Split a string into a list by a set of strings

Viewed 94

I am dealing with words written in Uzbek language. The language has the following letters:

alphabet = ["a", "b", "c", "d", "e", "f", "g", "g'", "h", "i", 
    "j", "k", "l", "m", "n", "ng", "o", "o'", "p", "q", "r", 
    "s", "sh", "t", "u", "v", "x", "y", "z"]

As you can see, there are letters with multiple characters like o', g' and sh. How can I split a word in this language into a list of Uzbek letters? So, for example, splitting the word "o'zbek" into ["o'", "z", "b", "e", "k"].

If I do the following:

word = "o'zbek"
letters = list(word)

It results in:

['o', "'", 'z', 'b', 'e', 'k']

which is incorrect as o and ' are not together.

I also tried using regex like this:

import re
expression = "|".join(alphabet)
re.split(expression, word)

But it results in:

['', "'", '', '', '', '']
3 Answers

To give priority to the more-than-one-character letters, first we sort the alphabet over the length of characters. Then pass it to a regex as you did with "|".join, and re.findall gives the list of splits:

import re

sorted_alphabet = sorted(alphabet, key=len, reverse=True)
regex = re.compile("|".join(sorted_alphabet))

def split_word(word):
    return re.findall(regex, word)

using:

>>> split_word("o'zbek")
["o'", 'z', 'b', 'e', 'k']

>>> split_word("asha")
['a', 'sh', 'a']

Something like this works.

double = {"o'", "ng", "g'", "sh"}

string = "o'zbek"
letters = []
while string:
    if string[:2] in double:
        letters.append(string[:2])
        string = string[2:]
    else:
        letters.append(string[0])
        string = string[1:]

If there are no triple letters or longer, you can list all the double letters in a set (finding an element in set is faster than finding it in list).

Than you go through the string, and try to find the double letters at the beginning of the string. If it is there, you store that in the list of letters.

import re
letters = re.findall("(o'|g'|ng|sh|[a-z])", string)

works too.

If you are looking for regex specifically, you could try to use re.findall with a pattern like so:

[a-fh-mp-rt-z]|[go]'?|ng?|sh?
  • [a-fh-mp-rt-z] - A character class holding all normal alphabets.
  • | : Or:
  • [go]'? - Either "g" or "o" followed by an optional quote.
  • | - Or:
  • ng? - A literal "n" followed by an optional "g".
  • | - Or:
  • sh? - A literal "s" followed by an optional "h".

See the online demo

import re
word = "o'zbek"
letters = re.findall("[a-fh-mp-rt-z]|[go]'?|ng?|sh?", word)
print(letters)

Prints:

["o'", 'z', 'b', 'e', 'k']

Note that you could also give priority to those "double" letters like so: [go]'|ng|sh|[a-z], kind of like how @MustafaAydin explained in his answer.

Related