3

我有一个名字作为字符串,在这个例子中是“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() 的库函数,但我想做“真正的编程”。

我该如何解决?

4

9 回答 9

11

我想你想要实现的是:

from string import capwords
capwords(name)

产生:

'Markus Johansson'

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

''.join([char.upper() if prev==' ' else char for char,prev in zip(name,' '+name)])
于 2009-03-04T09:31:19.833 回答
9
>>> "markus johansson".title()
'Markus Johansson'

内置的字符串方法是要走的路。

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

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

标准库仍然是要走的路。

于 2009-03-04T10:55:15.607 回答
5

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
于 2009-03-04T12:08:36.290 回答
4

字符串是不可变的。它们不能改变。您必须使用更改的内容创建一个新字符串。如果你想让每个 '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)
于 2009-03-04T09:31:16.323 回答
2

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

  • 约翰·亚当斯-史密斯
  • Joanne d'Arc
  • 让-吕克·德布鲁
  • 多纳蒂安·阿尔方斯·弗朗索瓦·德·萨德

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

  • 赫伯特·冯·洛克
  • 桑德·范多恩
  • 埃德温·范德萨德

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

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

于 2009-03-04T13:35:03.257 回答
1

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

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 开头的名字和姓氏的名称。

于 2009-03-04T09:37:03.970 回答
1

很多好的建议,所以我会在好公司里加上我自己的 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 字符的潜力。在这种情况下,使用模块的uppercaseandlowercase属性string很好,因为它们的内容会根据用户的语言环境而变化(即:系统相关,或者调用 locale.setlocale() 时)。我知道你想避免upper()在这个练习中使用,这很整洁......作为一个仅供参考,也upper()使用locale受控者setlocale(),所以使用的实践是对 API 的良好使用uppercaselowercase而不会太高级。也就是说,如果您需要在运行英语语言环境的系统上处理法语名称,您将需要更健壮的实现。

于 2009-03-04T11:42:23.577 回答
0

“真正的编程”?

我会使用 .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 的孙子”。

于 2009-03-04T11:07:10.650 回答
0
string = 'markus johansson'

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

# string == 'Markus Johansson'
于 2017-09-09T11:02:36.927 回答