无法通过字符修改正确解析字符串

问题描述 投票:0回答:3

我遇到了一个问题,我的Python代码没有正确返回一个函数调用,旨在在每个大写字母之前添加一个下划线字符,我不知道我哪里出错了。对于输出,只触及字符串中的“courseID”字,而其他两个字则不触及。

我想通过一个单词中的字母循环,寻找大写字母会起作用,但似乎并非如此。有人能让我知道我的代码可能出错的地方吗?

def parse_variables(string):
    new_string=''
    for letter in string:
        if letter.isupper():
            pos=string.index(letter)
            parsed_string=string[:pos] + '_' + string[pos:]
            new_string=''.join(parsed_string+letter)
        else:
            new_string=''.join(letter)
#        new_string=''.join(letter)
    return new_string.lower()

parse_variables("courseID pathID apiID")

当前输出是单个字母小写d,预期输出应该是course_id path_id api_id

python python-3.x string
3个回答
1
投票

修改后的代码的问题是index只找到字符串中大写字母的第一个出现。由于您具有相同大写字母的重复实例,因此该函数永远不会找到后续实例。您可以通过简单地连接带或不带下划线的字母来简化您的方法并避免此问题,具体取决于它们在您迭代时是否为大写。

例如:

def underscore_caps(s):
    result = ''
    for c in s:
        if c.isupper():
            result += f'_{c.lower()}'
        else:
            result += c

    return result

print(underscore_caps('courseID pathID apiID'))
# course_i_d path_i_d api_i_d

或者更简洁地使用列表理解和join

def underscore_caps(s):
    return ''.join([f'_{c.lower()}' if c.isupper() else c for c in s])

print(underscore_caps('courseID pathID apiID'))
# course_i_d path_i_d api_i_d

1
投票

我认为这里的正则表达式解决方案更容易理解。这需要以大写字母结尾的单词并添加下划线并使它们小写

import re

s = "courseID pathID apiID exampleABC DEF"

def underscore_lower(match):
    return "_" + match.group(1).lower()

pat = re.compile(r'(?<=[^A-Z\s])([A-Z]+)\b')

print(pat.sub(underscore_lower, s))
# course_id path_id api_id example_abc DEF

您可能必须使用该正则表达式才能使其完全符合您的要求。目前,在单词末尾需要大写字母,前面是一个既不是大写字母也不是空格的字符。然后它将这些字母设为小写,并在它们前面添加下划线。


1
投票

您的代码存在许多问题:

  1. string.index(letter)给出了letter第一次出现的指数,所以如果你有多个,例如Dpos只会更新到第一个位置。你可以通过使用enumerate迭代位置和字母来纠正这个问题。 for pos, letter in enumerate(string):
  2. 你在每个大写字母之前加上下划线,即_i_d
  3. 您通过引用string中的parsed_string=string[:pos] + '_' + string[pos:]来覆盖以前的编辑

纠正所有这些问题:

def parse_variables(string):
    new_string=''
    for pos, letter in enumerate(string):
        if letter.isupper() and pos+1 < len(string) and string[pos+1].isupper():
            new_string += f'_{letter}'
        else:
            new_string += letter
    return new_string.lower()

但更简单的方法是:

"courseID pathID apiID".replace('ID', '_id')

更新:

鉴于您想捕获的字符串种类繁多,似乎正则表达式是您要使用的工具:

import re

def parse_variables(string, pattern=r'(?<=[a-z])([A-Z]+)', prefix='_'):
    """Replace patterns in string with prefixed lowercase version.
    Default pattern is any substring of consecutive
    capital letters that occur after a lowercase letter."""

    foo = lambda pat: f'{prefix}{pat.group(1).lower()}'
    return re.sub(pattern, foo, text)

text = 'courseID pathProjects apiCode'
parse_variables(text)

>>> course_id path_projects api_code
© www.soinside.com 2019 - 2024. All rights reserved.