How can I get the specific character in string except the last one in Python?

Viewed 294

I have several strings like below. How can I get the dot, except the decimal dot?

Please note: I need the digit after the decimal. I don't want to lose the decimal dot and the digit after that.

For example:

"8.2"

"88.2"

"888.2"

"8.888.2"

"8.888.888.2"

The output will be like this:

"8.2"

"88.2"

"888.2"

"8888.2"

"8888888.2"
11 Answers

Use str.rpartition. It will work correctly even when there isn't a . in the input, as evident below.

def fix_number(n):
    a, sep, b = n.rpartition(".")
    return a.replace(".", "") + sep + b

for case in ["8.2", "88.2", "888.2", "8.888.2", "8.888.888.2", "8"]:
    print(case, fix_number(case))
8.2 8.2
88.2 88.2
888.2 888.2
8.888.2 8888.2
8.888.888.2 8888888.2
8 8

One way would be to split on the dots, then join together, treating the last one specially:

s = '8.888.888.2'
*whole, decimal = s.split('.')
res = ''.join(whole) + '.' + decimal  # gives: 8888888.2

You can use a similar method if you want to replace the thousands and/or decimal separators with another character:

s = '8.888.888.2'
*whole, decimal = s.split('.')
res = "'".join(whole) + ',' + decimal  # gives: 8'888'888,2

Another idea is to call str.replace() with the optional third argument count, which will replace only the first count occurrences of the character.

If we set count to be equal to the number of "." minus one we get the desired result:

words = ["8.2", "88.2", "888.2", "8.888.2", "8.888.888.2"]
new_words = []

for word in words:
    new_word = word.replace('.', '', word.count('.')-1)
    new_words.append(new_word)

print(new_words)

Output

['8.2', '88.2', '888.2', '8888.2', '8888888.2']

I have broken down the code into simpler lines for better understanding and readability.

Try this:

words = ["8", "8.2", "88.2", "888.2", "8.888.2", "8.888.888.2"]
changed_word = []
for word in words:
    split_word = word.split(".")
    if len(split_word) > 2:
        before_decimal = "".join(split_word[0:len(split_word)-1])
        after_decimal = split_word[-1]
        final_word = before_decimal + "." + after_decimal
    else:
        final_word = word
    changed_word.append(final_word)

print(changed_word)

The output is:

['8', '8.2', '88.2', '888.2', '8888.2', '8888888.2']

The next step: try to optimise this code in fewer lines.

You can use re here.

\.(?=.*\.)

Just replace with empty string.

See demo.

https://regex101.com/r/T9iX3B/1

import re

regex = r"\.(?=.*\.)"

test_str = ("\"8.2\"\n\n"
"\"88.2\"\n\n"
"\"888.2\"\n\n"
"\"8.888.2\"\n\n"
"\"8.888.888.2\" \n"
"8\n\n"
"the out put will be like this:\n\n"
" ")

subst = ""

# You can manually specify the number of replacements by changing the 4th argument
result = re.sub(regex, subst, test_str, 0, re.MULTILINE)

if result:
    print (result)
x = "8.888.888.22"
y = x.split(".")
z = "".join(y[:-1]) + "." + y[-1]
print(z)
# '8888888.22'

You need to find the last occurrence of the dot(.). And then before that index, replace all the dots with an empty character, and add the remaining part of the string:

s = "8.888.888.2"
last = -1
for index, item in enumerate(s):
    if item == ".":
        last = max(index, last)
if last != -1:
    s = s[:last].replace(".", "") + s[last:]
print(s)
a = ["8", "8.2", "88.2", "888.2", "8.888.2", "8.888.888.2"]

for x in a:
    if '.' not in x:
        print(x)
        continue

    ridx = x.rindex('.')
    print(x[:ridx].replace('.', '') + x[ridx:])

There are two ways I can imagine to solve your problem.

The first one is by parsing the string to another variable

example = 8888888.2
example = str(example) # In case that your input was in another type format
example_1 = example[-1:]

The output in this case would be "2".

For the second way, you can simple split the string into a list, and then you get only what you want:

example = 8888888.2
example = str(example)
example_2 = example.split('.') # Inside the parenthesis you can put the element you want to split the string, like a space, a comma, a dot
example_output = example[1]

In this case, the output was still the same "2" and in both cases you maintain your base variable just in case that you want the original input.

A simpler function:

def remove_dot(word):
    dot_cnt = word.count('.')
    if dot_cnt <= 1:
        return word
    else:
        word = word.replace(".", "", dot_cnt - 1)
        return word

print(remove_dot("8.888.888.2"))

output : = 8888888.2

Yet another solution, without special functions (inspired by the answer from @AKX).

def fix_number(n):
    return int( n.replace(".","") ) / ( 10 ** ('.' in n) )

for case in ["8.2", "88.2", "888.2", "8.888.2", "8.888.888.2", "8", ""8.888.888"]:
    print(case, fix_number(case))

The idea is that '.' in n returns 0 (False) if there are no dots, in which case we divide by 10^0 = 1. It returns 1 (True) if there are one or more dots, in which case we divide by 10.

8.2 8.2
88.2 88.2
888.2 888.2
8.888.2 8888.2
8.888.888.2 8888888.2
8 8.0
8.888.888 888888.8 <- not correct

As you can see, it returns a float even when there are no decimals. Not that the OP asked, but I think that's a nice feature :). However, it fails on the last test-case (which is not among the examples from the OP).

For this case we can replace the function with

def fix_number(n):
    return int( n.replace(".","") ) / ( 10 ** ('.' == n[-2]) )

but this fails on 8.

Fixing that leads us to

def fix_number(n):
    return int( n.replace(".","") ) / ( 10 ** (n.rfind('.') == max(0,len(n)-2)) )

which outputs

8.2 8.2
88.2 88.2
888.2 888.2
8.888.2 8888.2
8.888.888.2 8888888.2
8 8.0
8.888.888 8888888.0

But at this point is gets a bit ridiculous :). Also the answer by @AKX is about 3.5 times faster.

Related