Python 中字符串标题大小写问题

发布于 2024-07-14 22:07:24 字数 545 浏览 4 评论 0原文

我有一个字符串形式的名称,在本例中为“markus johansson”。

我正在尝试编写一个使“m”和“j”大写的程序:

name = "markus johansson"

for i in range(1, len(name)):
    if name[0] == 'm':
        name[0] = "M"
    if name[i] == " ":
        count = name[i] + 1
    if count == 'j':    
            name[count] = 'J'  

我很确定这应该可行,但它给了我这个错误:

File "main.py", line 5 in <module> 
   name[0] = "M" 
TypeError: 'str' object does support item assignment 

我知道有一个名为 .title() 的库函数,但我想做“真正的编程”。

我该如何解决?

I have a name as a string, in this example "markus johansson".

I'm trying to code a program that makes 'm' and 'j' uppercase:

name = "markus johansson"

for i in range(1, len(name)):
    if name[0] == 'm':
        name[0] = "M"
    if name[i] == " ":
        count = name[i] + 1
    if count == 'j':    
            name[count] = 'J'  

I'm pretty sure this should work, but it gives me this error:

File "main.py", line 5 in <module> 
   name[0] = "M" 
TypeError: 'str' object does support item assignment 

I know there is a library function called .title(), but I want to do "real programming".

How do I fix this?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(9

忘年祭陌 2024-07-21 22:07:24

我想你想要实现的是:

from string import capwords
capwords(name)

产生:

'Markus Johansson'

编辑:好的,我看到你想推倒一扇敞开的门。
这是低级实现。

''.join([char.upper() if prev==' ' else char for char,prev in zip(name,' '+name)])

I guess that what you're trying to achieve is:

from string import capwords
capwords(name)

Which yields:

'Markus Johansson'

EDIT: OK, I see you want to tear down a open door.
Here's low level implementation.

''.join([char.upper() if prev==' ' else char for char,prev in zip(name,' '+name)])
新一帅帅 2024-07-21 22:07:24
>>> "markus johansson".title()
'Markus Johansson'

内置字符串方法是可行的方法。

编辑:
我看你想重新发明轮子。 有什么特别的原因吗?
您可以从任意数量的复杂方法中进行选择,例如:

' '.join(j[0].upper()+j[1:] for j in "markus johansson".split())

标准库仍然是最佳选择。

>>> "markus johansson".title()
'Markus Johansson'

Built in string methods are the way to go.

EDIT:
I see you want to re-invent the wheel. Any particular reason ?
You can choose from any number of convoluted methods like:

' '.join(j[0].upper()+j[1:] for j in "markus johansson".split())

Standard Libraries are still the way to go.

紙鸢 2024-07-21 22:07:24

string.capwords() (在 string.py)

# Capitalize the words in a string, e.g. " aBc  dEf " -> "Abc Def".
def capwords(s, sep=None):
    """capwords(s, [sep]) -> string

    Split the argument into words using split, capitalize each
    word using capitalize, and join the capitalized words using
    join. Note that this replaces runs of whitespace characters by
    a single space.

    """
    return (sep or ' ').join(x.capitalize() for x in s.split(sep))

str.title() (在 stringobject.c)

PyDoc_STRVAR(title__doc__,
"S.title() -> string\n\
\n\
Return a titlecased version of S, i.e. words start with uppercase\n\
characters, all remaining cased characters have lowercase.");
static PyObject*
string_title(PyStringObject *self)
{
    char *s = PyString_AS_STRING(self), *s_new;
    Py_ssize_t i, n = PyString_GET_SIZE(self);
    int previous_is_cased = 0;
    PyObject *newobj = PyString_FromStringAndSize(NULL, n);
    if (newobj == NULL)
        return NULL;
    s_new = PyString_AsString(newobj);
    for (i = 0; i < n; i++) {
        int c = Py_CHARMASK(*s++);
        if (islower(c)) {
            if (!previous_is_cased)
                c = toupper(c);
            previous_is_cased = 1;
        } else if (isupper(c)) {
            if (previous_is_cased)
                c = tolower(c);
            previous_is_cased = 1;
        } else
            previous_is_cased = 0;
        *s_new++ = c;
    }
    return newobj;
}

str.title() 纯Python

class String(str):
    def title(self):
        s = []
        previous_is_cased = False
        for c in self:
            if c.islower():
               if not previous_is_cased:
                  c = c.upper()
               previous_is_cased = True
            elif c.isupper():
               if previous_is_cased:
                  c = c.lower()
               previous_is_cased = True
            else:
               previous_is_cased = False
            s.append(c)
        return ''.join(s)

示例:

>>> s = ' aBc  dEf '
>>> import string
>>> string.capwords(s)
'Abc Def'
>>> s.title()
' Abc  Def '
>>> s
' aBc  dEf '
>>> String(s).title()
' Abc  Def '
>>> String(s).title() == s.title()
True

string.capwords() (defined in string.py)

# Capitalize the words in a string, e.g. " aBc  dEf " -> "Abc Def".
def capwords(s, sep=None):
    """capwords(s, [sep]) -> string

    Split the argument into words using split, capitalize each
    word using capitalize, and join the capitalized words using
    join. Note that this replaces runs of whitespace characters by
    a single space.

    """
    return (sep or ' ').join(x.capitalize() for x in s.split(sep))

str.title() (defined in stringobject.c)

PyDoc_STRVAR(title__doc__,
"S.title() -> string\n\
\n\
Return a titlecased version of S, i.e. words start with uppercase\n\
characters, all remaining cased characters have lowercase.");
static PyObject*
string_title(PyStringObject *self)
{
    char *s = PyString_AS_STRING(self), *s_new;
    Py_ssize_t i, n = PyString_GET_SIZE(self);
    int previous_is_cased = 0;
    PyObject *newobj = PyString_FromStringAndSize(NULL, n);
    if (newobj == NULL)
        return NULL;
    s_new = PyString_AsString(newobj);
    for (i = 0; i < n; i++) {
        int c = Py_CHARMASK(*s++);
        if (islower(c)) {
            if (!previous_is_cased)
                c = toupper(c);
            previous_is_cased = 1;
        } else if (isupper(c)) {
            if (previous_is_cased)
                c = tolower(c);
            previous_is_cased = 1;
        } else
            previous_is_cased = 0;
        *s_new++ = c;
    }
    return newobj;
}

str.title() in pure Python

class String(str):
    def title(self):
        s = []
        previous_is_cased = False
        for c in self:
            if c.islower():
               if not previous_is_cased:
                  c = c.upper()
               previous_is_cased = True
            elif c.isupper():
               if previous_is_cased:
                  c = c.lower()
               previous_is_cased = True
            else:
               previous_is_cased = False
            s.append(c)
        return ''.join(s)

Example:

>>> s = ' aBc  dEf '
>>> import string
>>> string.capwords(s)
'Abc Def'
>>> s.title()
' Abc  Def '
>>> s
' aBc  dEf '
>>> String(s).title()
' Abc  Def '
>>> String(s).title() == s.title()
True
浅唱々樱花落 2024-07-21 22:07:24

字符串是不可变的。 它们无法改变。 您必须使用更改的内容创建一个新字符串。
如果你想让每个“j”大写:

def make_uppercase_j(char):
    if char == 'j':
        return 'J'
    else:
        return char
name = "markus johansson"
''.join(make_uppercase_j(c) for c in name)

Strings are immutable. They can't be changed. You must create a new string with the changed content.
If you want to make every 'j' uppercase:

def make_uppercase_j(char):
    if char == 'j':
        return 'J'
    else:
        return char
name = "markus johansson"
''.join(make_uppercase_j(c) for c in name)
咆哮 2024-07-21 22:07:24

如果您正在寻找更通用的名称解决方案,您还应该查看以下示例:

  • John Adams-Smith
  • Joanne d'Arc
  • Jean-Luc de'Breu
  • Donatien Alphonse François de Sade

另外,名称的某些部分不应以大写字母,例如:

  • Herbert von Locke
  • Sander van Dorn
  • Edwin van der Sad

因此,如果您正在考虑创建更通用的解决方案,请记住所有这些小事情。

(这将是运行测试驱动开发的完美场所,您的方法/函数必须遵循所有这些条件)

If you're looking into more generic solution for names, you should also look at following examples:

  • John Adams-Smith
  • Joanne d'Arc
  • Jean-Luc de'Breu
  • Donatien Alphonse François de Sade

Also some parts of the names shouldn't start with capital letters, like:

  • Herbert von Locke
  • Sander van Dorn
  • Edwin van der Sad

so, if you're looking into creating a more generic solution, keep all those little things in mind.

(This would be a perfect place to run a test-driven development, with all those conditions your method/function must follow).

意犹 2024-07-21 22:07:24

如果我正确理解你的原始算法,这就是你想要做的:

namn = list("markus johansson")

if namn[0] == 'm':
    namn[0] = "M"

count = 0

for i in range(1, len(namn)):
    if namn[i] == " ":
        count = i + 1
    if count and namn[count] == 'j':    
        namn[count] = 'J'

print ''.join(namn)

当然,有一百万种更好的方法(“想要的”方法)来完成你想要做的事情,就像 vartec 的答案所示。 :)

就目前情况而言,您的代码仅适用于名字和姓氏分别以 J 和 M 开头的名称。

If I understand your original algorithm correctly, this is what you want to do:

namn = list("markus johansson")

if namn[0] == 'm':
    namn[0] = "M"

count = 0

for i in range(1, len(namn)):
    if namn[i] == " ":
        count = i + 1
    if count and namn[count] == 'j':    
        namn[count] = 'J'

print ''.join(namn)

Of course, there's a million better ways ("wannabe" ways) to do what you're trying to do, like as shown in vartec's answer. :)

As it stands, your code only works for names that start with a J and an M for the first and last names, respectively.

梦断已成空 2024-07-21 22:07:24

有很多好的建议,所以我会在好的公司中添加我自己的 2 美分:-)

我假设您想要一些更通用的东西,可以处理的不仅仅是以 'm' 和 'j' 开头的名称。 您可能还需要考虑连字符的名称(例如 Markus Johnson-Smith),连字符后也有大写字母。

from string import lowercase, uppercase
name = 'markus johnson-smith'

state = 0
title_name = []

for c in name:
    if c in lowercase and not state:
        c = uppercase[lowercase.index(c)]
        state = 1
    elif c in [' ', '-']:
        state = 0
    else:
        state = 1 # might already be uppercase

    title_name.append(c)

print ''.join(title_name)

最后需要注意的是非 ASCII 字符的潜力。 在这种情况下,使用 string 模块的 uppercaselowercase 属性是很好的,因为它们的内容会根据用户的区域设置而变化(即:系统 -相关的,或者当 locale.setlocale() 被调用时)。 我知道您想避免在本练习中使用 upper(),这非常简洁......仅供参考,upper() 使用 locale code> 也由 setlocale() 控制,因此使用 uppercaselowercase 的做法是 API 的良好使用,但不会变得太高 -等级。 也就是说,如果您需要在运行英语语言环境的系统上处理法语名称,您将需要更强大的实现。

Plenty of good suggestions, so I'll be in good company adding my own 2 cents :-)

I'm assuming you want something a little more generic that can handle more than just names starting with 'm' and 'j'. You'll probably also want to consider hyphenated names (like Markus Johnson-Smith) which have caps after the hyphen too.

from string import lowercase, uppercase
name = 'markus johnson-smith'

state = 0
title_name = []

for c in name:
    if c in lowercase and not state:
        c = uppercase[lowercase.index(c)]
        state = 1
    elif c in [' ', '-']:
        state = 0
    else:
        state = 1 # might already be uppercase

    title_name.append(c)

print ''.join(title_name)

Last caveat is the potential for non-ascii characters. Using the uppercase and lowercase properties of the string module is good in this case becase their contents change depending on the user's locale (ie: system-dependent, or when locale.setlocale() is called). I know you want to avoid using upper() for this exercise, and that's quite neat... as an FYI, upper() uses the locale controlled by setlocale() too, so the practice of use uppercase and lowercase is a good use of the API without getting too high-level. That said, if you need to handle, say, French names on a system running an English locale, you'll need a more robust implementation.

吻安 2024-07-21 22:07:24

“真正的编程”?

我会使用 .title(),我是一个真正的程序员。

或者我会使用正则表达式

re.sub(r"(^|\s)[a-z]", lambda m: m.group(0).upper(), "this   is a set of  words")

这表示“如果文本的开头或空白字符后跟一个小写字母”(英语 - 可能不支持其他语言),然后对于每个匹配将匹配文本转换为大写字母-案件。 由于匹配文本是空格和小写字母,因此效果很好。

如果您希望将其作为低级代码,则可以使用以下方法。 这里我只允许空格作为分隔符(但你可能想支持换行符和其他字符)。 另一方面,“string.lowercase”是国际化的,因此如果您位于另一个区域设置,那么它在大多数情况下仍然可以工作。 如果您不想这样做,请使用 string.ascii_lowercase。

import string

def title(s):
    # Capitalize the first character
    if s[:1] in string.lowercase:
        s = s[0].upper() + s[1:]

    # Find spaces
    offset = 0
    while 1:
        offset = s.find(" ", offset)
        # Reached the end of the string or the
        # last character is a space
        if offset == -1 or offset == len(s)-1:
            break

        if s[offset+1:offset+2] in string.lowercase:
            # Is it followed by a lower-case letter?
            s = s[:offset+1] + s[offset+1].upper() + s[offset+2:]
            # Skip the space and the letter
            offset += 2
        else:
            # Nope, so start searching for the next space
            offset += 1

    return s

为了详细说明我对此答案的评论,这个问题只能是出于好奇心的练习。 真实姓名有特殊的大写规则:“Johannes Diderik van der Waals”中的“van der”从不大写,“Farrah Fawcett-Majors”有“M”,“Cathal Ó hEochaidh”使用非 ASCII Ó 和 h ,它将“Eochaidh”修改为“Eochaidh 的孙子”。

"real programming"?

I would use .title(), and I'm a real programmer.

Or I would use regular expressions

re.sub(r"(^|\s)[a-z]", lambda m: m.group(0).upper(), "this   is a set of  words")

This says "If the start of the text or a whitespace character is followed by a lower-case letter" (in English - other languages are likely not supported), then for each match convert the match text to upper-case. Since the match text is the space and the lower-case letter, this works just fine.

If you want it as low-level code then the following works. Here I only allow space as the separator (but you may want to support newline and other characters). On the other hand, "string.lowercase" is internationalized, so if you're in another locale then it will, for the most part, still work. If you don't want that then use string.ascii_lowercase.

import string

def title(s):
    # Capitalize the first character
    if s[:1] in string.lowercase:
        s = s[0].upper() + s[1:]

    # Find spaces
    offset = 0
    while 1:
        offset = s.find(" ", offset)
        # Reached the end of the string or the
        # last character is a space
        if offset == -1 or offset == len(s)-1:
            break

        if s[offset+1:offset+2] in string.lowercase:
            # Is it followed by a lower-case letter?
            s = s[:offset+1] + s[offset+1].upper() + s[offset+2:]
            # Skip the space and the letter
            offset += 2
        else:
            # Nope, so start searching for the next space
            offset += 1

    return s

To elaborate on my comment to this answer, this question can only be an exercise for curiosity's sake. Real names have special capitalization rules: the "van der" in "Johannes Diderik van der Waals" is never capitalized, "Farrah Fawcett-Majors" has the "M", and "Cathal Ó hEochaidh" uses the non-ASCII Ó and h, which modify "Eochaidh" to mean "grandson of Eochaidh".

末蓝 2024-07-21 22:07:24
string = 'markus johansson'

string = ' '.join(substring[0].upper() + substring[1:] for substring in string.split(' '))

# string == 'Markus Johansson'
string = 'markus johansson'

string = ' '.join(substring[0].upper() + substring[1:] for substring in string.split(' '))

# string == 'Markus Johansson'
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文