为什么在Python3中为字符串编制索引而不是切片时会出现索引器?

为什么在Python3中为字符串编制索引而不是切片时会出现索引器?,python,string,list,Python,String,List,我是编程新手,正在试验Python3。我发现了一些关于IndexError的主题,但似乎没有一个对这种特定情况有帮助 我编写了一个函数,它打开一个文本文件,一次读取一行,然后将该行分割成单独的字符串,每个字符串都附加到一个特定的列表中(记录行中每个“列”一个列表)。大多数切片是多个字符[x:y],但有些是单个字符[x] 我收到一条索引器:字符串索引超出范围的消息,而据我所知,它不是。这就是功能: def read_recipe_file(): recipe_id = [] rec

我是编程新手,正在试验Python3。我发现了一些关于IndexError的主题,但似乎没有一个对这种特定情况有帮助

我编写了一个函数,它打开一个文本文件,一次读取一行,然后将该行分割成单独的字符串,每个字符串都附加到一个特定的列表中(记录行中每个“列”一个列表)。大多数切片是多个字符[x:y],但有些是单个字符[x]

我收到一条
索引器:字符串索引超出范围的消息,而据我所知,它不是。这就是功能:

def read_recipe_file():
    recipe_id = []
    recipe_book = []
    recipe_name = []
    recipe_page = []
    ingred_1 = []
    ingred_1_qty = []
    ingred_2 = []
    ingred_2_qty = []
    ingred_3 = []
    ingred_3_qty = []

    f = open('recipe-file.txt', 'r')  # open the file 
    for line in f:
        # slice out each component of the record line and store it in the appropriate list
        recipe_id.append(line[0:3])
        recipe_name.append(line[3:23])
        recipe_book.append(line[23:43])
        recipe_page.append(line[43:46])
        ingred_1.append(line[46]) 
        ingred_1_qty.append(line[47:50])
        ingred_2.append(line[50]) 
        ingred_2_qty.append(line[51:54])
        ingred_3.append(line[54]) 
        ingred_3_qty.append(line[55:])
    f.close()
return recipe_id, recipe_name, recipe_book, recipe_page, ingred_1, ingred_1_qty, ingred_2, ingred_2_qty, ingred_3, \
       ingred_3_qty
这是回溯:

Traceback (most recent call last):
  File "recipe-test.py", line 84, in <module>
    recipe_id, recipe_book, recipe_name, recipe_page, ingred_1, ingred_1_qty, ingred_2, ingred_2_qty, ingred_3, ingred_3_qty = read_recipe_file()
  File "recipe-test.py", line 27, in read_recipe_file
    ingred_1.append(line[46])
失败之处在于:

ingred_1.append(line[46])
我试图读取的文本文件的每一行中都有超过46个字符,因此我不明白为什么会出现越界错误(下面是一个示例行)。如果我将代码更改为:

ingred_1.append(line[46:])
要读取一个片段,而不是一个特定字符,该行将正确执行,程序将在这一行失败:

ingred_2.append(line[50])
这让我觉得它与从字符串中附加一个字符有关,而不是多个字符的片段

下面是我正在阅读的文本文件中的一行示例:

001012120038005002两份烤面包上的奶酪

我应该补充一点,我很清楚这不是一个好的代码——通常我可以通过很多方法来改进程序,但就我所知,代码应该实际工作。

如果文件中的某些行是空的或至少是短的,就会发生这种情况。文件末尾的换行是一个常见的原因,因为这是一个额外的空行。调试此类案例的最佳方法是捕获异常,并调查失败的特定
(几乎肯定不会是您复制的示例行):

捕捉这个异常通常也是正确处理错误的方法:你已经发现了一个病态的病例,现在你可以考虑该怎么办了。例如,您可以:

  • 继续
    ,它将自动跳过处理该行
  • 记录一些内容,然后
    继续
  • 通过提出一个新的、更具主题性的例外来摆脱困境:例如
    raisevalueerror(“行太短”)
如果这表示需要修复的输入文件存在问题,则打印相关内容(无论是否继续)几乎总是一个好主意。如果它是一件相对琐碎的事情,并且您知道它不会在其余处理过程中导致错误流,那么静默继续是一个不错的选择。您可能希望通过提前检测“完全空”案例来区分“太短”案例和“完全空”案例,例如在循环的顶部执行此操作:

if not line:
    # Skip blank lines
    continue
并对另一种情况下的错误进行适当处理


将其更改为切片的原因是字符串切片从不失败。如果切片中的两个索引都在字符串之外(在同一方向),则将得到一个空字符串-例如:

>>> 'abc'[4]
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
IndexError: string index out of range
>>> 'abc'[4:]
''
>>> 'abc'[4:7]
''
>“abc”[4]
回溯(最近一次呼叫最后一次):
文件“”,第1行,在
索引器错误:字符串索引超出范围
>>>“abc”[4:]
''
>>>“abc”[4:7]
''

您的代码在
行[46]
上失败,因为
包含的字符少于47个。切片操作[46:][/code>行仍然有效,因为超出范围的字符串切片返回空字符串

您可以通过更换来确认线路是否太短

ingred_1.append(line[46])


有空行吗?这将导致此错误。输入文件中是否有选项卡?试着打印行长。我想unutbu已经搞定了-在源文本文件的末尾有一个额外的换行符。删除它显示了附加代码中的另一个错误(忘记了某些列表名称末尾的[i]),但当我修复该错误时,一切都按预期进行了:<代码>行[100000:://code>始终是合法的,无论行长如何。您可能需要添加一个
尝试
,但
块和打印
len(line)
出现异常。@RichCairns:很高兴您解决了这个问题。请随意接受已经发布的其中一个答案。谢谢@michael-但是
line
肯定包含超过47个字符-我在OP中发布了源文件中的一行示例。我忽略了添加的内容(我的错)是源文件中的所有行的长度都完全相同。我认为,OP中的评论者已经抓住了它——在源文件的末尾有一个额外的换行符。不,
line[46]
不会导致
索引器出现,如果
line
至少包含47个字符。请注意,空行包含的字符少于47个。如果您恢复到以前版本的输入文件并实现
try。。。捕获
构造。
>>> 'abc'[4]
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
IndexError: string index out of range
>>> 'abc'[4:]
''
>>> 'abc'[4:7]
''
ingred_1.append(line[46])
try:
    ingred_1.append(line[46])
except IndexError:
    print('line = "%s", length = %d' % (line, len(line)))