0

I have a python challenge that if given a string with '_' or '-' in between each word such as the_big_red_apple or the-big-red-apple to convert it to camel case. Also if the first word is uppercase keep it as uppercase. This is my code. Im not allowed to use the re library in the challenge however but I didn't know how else to do it.

from re import sub
def to_camel_case(text):
    if text[0].isupper():
      text = sub(r"(_|-)+"," ", text).title().replace(" ", "")
    else:
      text = sub(r"(_|-)+"," ", text).title().replace(" ", "")
      text = text[0].lower() + text[1:]
      
    return print(text)
  • 1
    You're not allowed to use `re`, but you want to know, among several questions, what all the `re`-specific stuff, which you claim to be *your* code, means? How did you write the code if you didn't understand it? What is your primary question? Asking several questions in one will get this closed as lacking focus. – ShadowRanger Jul 06 '22 at 02:22
  • The "r" stands for raw string. It converts a string into raw string literal. See this : https://stackoverflow.com/questions/2081640/what-exactly-do-u-and-r-string-prefixes-do-and-what-are-raw-string-literals – Deepeshkumar Jul 06 '22 at 02:25
  • Yeah, for the challenge I cant I dont think but im curious to learn what the re specific stuff means – Daniel Dubinko Jul 06 '22 at 02:27
  • The condition "if text[0].isupper()" is unnecessary if the input is always going to be like "the_big_red_apple". – Deepeshkumar Jul 06 '22 at 02:32
  • @DanielDubinko you want help in solving the challenge without the use of "re" library or you are just interested to understand the online piece of code? Be specific. – Deepeshkumar Jul 06 '22 at 02:37

4 Answers4

0

Word delimiters can be - dash or _ underscore. Let's simplify, making them all underscores:

    text = text.replace('-', '_')

Now we can break out words:

    words = text.split('_')

With that in hand it's simple to put them back together:

    text = ''.join(map(str.capitalize, words))

or more verbosely, with a generator expression, assign ''.join(word.capitalize() for word in words).

I leave "finesse the 1st character" as an exercise to the reader.


If you RTFM you'll find it contains a wealth of knowledge. https://docs.python.org/3/library/re.html#raw-string-notation

'+'

Causes the resulting RE to match 1 or more repetitions of the preceding RE. ab+ will match ‘a’ followed by any non-zero number of ‘b’s

The effect of + is turn both

  • db_rows_read and
  • db__rows_read

into DbRowsRead.

Also,

Raw string notation (r"text") keeps regular expressions sane.

The regex in your question doesn't exactly need a raw string, as it has no crazy punctuation like \ backwhacks. But it's a very good habit to always put a regex in an r-string, Just In Case. You never know when code maintenance will tack on additional elements, and who wants a subtle regex bug on their hands?

J_H
  • 17,926
  • 4
  • 24
  • 44
0

Try this:

  • First, replace all the delimiters into a single one, i.e. str.replace('_', '-')
  • Split the string on the str.split('-') standardized delimiter
  • Capitalize each string in list, i.e. str.capitilize()
  • Join the capitalize string with str.join
>>> s = "the_big_red_apple"
>>> s.replace('_', '-').split('-')
['the', 'big', 'red', 'apple']

>>> ''.join(map(str.capitalize, s.replace('_', '-').split('-')))
'TheBigRedApple'

>> ''.join(word.capitalize() for word in s.replace('_', '-').split('-'))
'TheBigRedApple'

If you need to lowercase the first char, then:

>>> camel_mile = lambda x: x[0].lower() + x[1:]
>>> s = 'TheBigRedApple'
>>> camel_mile(s)
'theBigRedApple'

Alternative,

  • First replace all delimiters to space str.replace('_', ' ')
  • Titlecase the string str.title()
  • Remove space from string, i.e. str.replace(' ', '')
>>> s = "the_big_red_apple"
>>> s.replace('_', ' ').title().replace(' ', '')
'TheBigRedApple'

Another alternative,

  • Iterate through the characters and then keep a pointer/note on previous character, i.e. for prev, curr in zip(s, s[1:])
  • check if the previous character is one of your delimiter, if so, uppercase the current character, i.e. curr.upper() if prev in ['-', '_'] else curr
  • skip whitepace characters, i.e. if curr != " "
  • Then add the first character in lowercase, [s[0].lower()]
>>> chars = [s[0].lower()] + [curr.upper() if prev in ['-', '_'] else curr  for prev, curr in zip(s, s[1:])  if curr != " "]
>>> "".join(chars)
'theBigRedApple'

Yet another alternative,

  • Replace/Normalize all delimiters into a single one, s.replace('-', '_')
  • Convert it into a list of chars, list(s.replace('-', '_'))
  • While there is still '_' in the list of chars, keep
    • find the position of the next '_'
    • replacing the character after '_' with its uppercase
    • replacing the '_' with ''
>>> s = 'the_big_red_apple'
>>> s_list = list(s.replace('-', '_'))
>>> while '_' in s_list:
...     where_underscore = s_list.index('_')
...     s_list[where_underscore+1] = s_list[where_underscore+1].upper()
...     s_list[where_underscore] = ""
... 
>>> "".join(s_list)
'theBigRedApple'

or

>>> s = 'the_big_red_apple'
>>> s_list = list(s.replace('-', '_'))
>>> while '_' in s_list:
...     where_underscore = s_list.index('_')
...     s_list[where_underscore:where_underscore+2] = ["", s_list[where_underscore+1].upper()]
... 
>>> "".join(s_list)
'theBigRedApple'

Note: Why do we need to convert the string to list of chars? Cos strings are immutable, 'str' object does not support item assignment


BTW, the regex solution can make use of some group catching, e.g.

>>> import re

>>> s = "the_big_red_apple"

>>> upper_regex_group = lambda x: x.group(1).upper()
>>> re.sub("[_|-](\w)", upper_regex_group, s)
'theBigRedApple'

>>> re.sub("[_|-](\w)", lambda x: x.group(1).upper(), s)
'theBigRedApple'
alvas
  • 115,346
  • 109
  • 446
  • 738
0

You can try it like this :

def to_camel_case(text):
    s = text.replace("-", " ").replace("_", " ")
    s = s.split()
    if len(text) == 0:
        return text
    return s[0] + ''.join(i.capitalize() for i in s[1:])
    
print(to_camel_case('momo_es-es'))

the output of print(to_camel_case('momo_es-es')) is momoEsEs

monim
  • 3,641
  • 2
  • 10
  • 25
0

r"..." refers to Raw String in Python which simply means treating backlash \ as literal instead of escape character.

And (_|-)[+] is a Regular Expression that match the string containing one or more - or _ characters.

  • (_|-) means matching the string that contains - or _.
  • + means matching the above character (- or _) than occur one or more times in the string.

In case you cannot use re library for this solution:

def to_camel_case(text):
    # Since delimiters can have 2 possible answers, let's simplify it to one.
    # In this case, I replace all `_` characters with `-`, to make sure we have only one delimiter.
    text = text.replace("_", "-") # the_big-red_apple => the-big-red-apple
    
    # Next, we should split our text into words in order for us to iterate through and modify it later.
    words = text.split("-") # the-big-red-apple => ["the", "big", "red", "apple"]

    # Now, for each word (except the first word) we have to turn its first character to uppercase.
    for i in range(1, len(words)):
        # `i`start from 1, which means the first word IS NOT INCLUDED in this loop.
        word = words[i]
        
        # word[1:] means the rest of the characters except the first one
        # (e.g. w = "apple" => w[1:] = "pple")
        words[i] = word[0].upper() + word[1:].lower()
        # you can also use Python built-in method for this:
        # words[i] = word.capitalize()

    # After this loop, ["the", "big", "red", "apple"] => ["the", "Big", "Red", "Apple"]

    # Finally, we put the words back together and return it
    # ["the", "Big", "Red", "Apple"] => theBigRedApple
    return "".join(words)


print(to_camel_case("the_big-red_apple"))