【问题标题】:Is there a way to use "for loop" in the specific range with strings?有没有办法在字符串的特定范围内使用“for循环”?
【发布时间】:2013-07-12 17:43:51
【问题描述】:

你好 stackoverflow 用户,

我想知道如何将 for 循环与字符串一起使用。

例如,

有一个文件(file.txt)之类的,

======================

Initial Value

    1 2 3
    3 4 5
    5 6 7

Middle Value           <---From Here

    3 5 6
    5 8 8
    6 9 8                  <---To Here

Last Value

    5 8 7
    6 8 7
    5 5 7

===================

我想只在“中值”中修改文件的部分并写一个输出文件

修改后。

我认为如果我使用“if and for”语句,这可能会得到解决。

我想到了类似的代码

with open('file.txt') as f, open('out.txt', 'w') as f2:

       for line in f:
           sp1 = line.split()
           line = " ".join(sp1) + '\n'
           if line == 'Middle':
              "Do something until line == 'Last'"

我被"Do something until line == 'Last'" 卡住了。

感谢任何 cmets。

谢谢。

【问题讨论】:

  • 您是说文件总是有一行读取中间值吗?
  • 您几乎已经回答了自己的问题,请尝试使用while 循环
  • @AM_Hawk:while 循环在这里有什么帮助?
  • @abarnert: while middle == true 执行你的操作然后中断
  • @AM_Hawk:但是在while 循环中,您没有迭代外部for 循环,所以这只是围绕同一行的无限循环,这似乎不是很有用。您必须重写代码才能显式地对文件进行迭代(无论是 nextreadline 等),而不是仅仅循环它,这很难简化事情。

标签: python file if-statement for-loop


【解决方案1】:

共有三种基本方法。


首先是使用状态机。您可以构建一个真实的状态机,但在这种情况下,状态和转换非常简单,只需使用一个标志就可以更简单地伪造它:

state = 0
for line in f:
    sp1 = line.split()
    line = " ".join(sp1) + '\n'
    if state == 0:
        if line == 'Middle\n':
            state = 1
    elif state == 1:
        if line == 'Last\n':
            state = 2
        else:
            # Thing you do until line == 'Last\n'
    else:
        # nothing to do after Last, so you could leave it out

请注意,我检查的是'Middle\n',而不是'Middle'。如果您查看上面构建line 的方式,它无法匹配后者,因为您总是添加'\n'。但还要注意,在您的示例数据中,该行是'Middle Value\n',而不是'Middle',所以如果在您的真实数据中是这样,您必须在此处处理。是line == 'Middle Value\n'line.startswith('Middle') 还是其他,取决于您的实际数据,只有您自己知道。


或者,您可以将其分解为循环:

for line in f:
    sp1 = line.split()
    line = " ".join(sp1) + '\n'
    if line == 'Middle\n':
        break
for line in f:
    sp1 = line.split()
    line = " ".join(sp1) + '\n'
    if line == 'Last\n':
        break
    else:
        # Thing you do until line == 'Last\n'
for line in f:
    # Nothing to do here, so you could leave the loop out

这个也有变化。例如:

lines = (" ".join(line.split()) + '\n' for line in f)
lines = dropwhile(lambda line: line != 'Middle', lines)
middle = takewhile(lambda line: line != 'End', lines)
for line in middle:
    # Thing you want to do

最后,您可以在之前将文件拆分为行,而不是之后。这更难迭代执行,所以让我们将整个文件读入内存来展示这个想法:

contents = f.read()
_, _, rest = contents.partition('\nMiddle\n')
middle, _, _ = rest.partition('\nEnd')
for line in middle.splitlines():
    # Thing you want to do

如果将整个文件读入内存会浪费太多空间或需要很长时间才能开始,mmap 是你的朋友。

【讨论】:

  • 把它分成循环是个好主意
  • @Stephan:我认为真正让这篇文章具有可读性的是第二步。无论您使用标志、重复相同内容的多个循环,还是将文件视为字符流而不是行的代码,它都会变得丑陋(除非您忽略大文件问题,就像我在上一个示例中所做的那样) .但是这三者中的任何一个都可以很容易地分别用状态机、迭代器管道或对mmap 的简单拆分进行抽象,然后它们都变得可读。
  • 是的,我什至没有费心分析你的最后一个,因为存在更简单的解决方案,但是这个线程中有很多好主意并且没有多少赞成票,这个社区对他们的批准点击很吝啬.
  • @Stephan:是的,对于非常简单的情况,通常不值得将它们考虑到下一步。这取决于具体情况——你是在截止日期前 2 天,而推迟​​它会使你的股票期权价值减少 100 万美元,还是你在自学 Python 的一个新领域或一个新的应用领域是为了好玩? (当然在现实中,你可能介于两者之间,但你明白了。)
【解决方案2】:

我会将这个过程编码为一个简单的 FSM(Finite-State Machine 或更具体地说是 event-driven Finite-state machine):

with open('file.txt') as f, open('out.txt', 'w') as f2:
    state = 1
    for line in f:
        if line == 'Middle Value\n':
            state = 2
            continue  # unless there's something to do upon entering the state
        elif line == 'Last Value\n':  # might want to just test for blank line `\n'
            state = 3
            continue  # unless there's something to do upon entering the state

        # otherwise process to line based on the current value of "state"
        if state == 1:      # before 'Middle Value' has been seen
            pass
        elif state == 2:    # after 'Middle Value' has been seen
            pass
        else:               # after 'Last Value' (or a blank line after 
            pass            # 'Middle Value') has been seen

只需将pass 语句替换为在读取输入文件时可以执行的任何操作即可。

【讨论】:

  • 当我使用这段代码时,除了一件事之外它可以工作。 “继续”语句将删除输出文件中的“中间值”和“最后值”字符串。两个词修改后怎么保留?
  • continue 意味着将跳过该循环迭代中的所有进一步处理,包括 if state == 检查。要么完全删除它以让后者发生,要么将其保留并在声明之前执行任何需要完成的操作。
【解决方案3】:

在您的 if line == 'Middle': 中,您可以翻转一个布尔标志,允许您输入另一个 if inMiddle and line !=last` 语句,然后您可以在其中修改您的数字

你可以用这个替换你的 for 循环。

inMiddle = false
for line in f:
    sp1 = line.split()
    line = "".join(sp1) + '\n'

    if line == 'Middle':
        inMiddle = true

    if inMiddle and line != 'Last':
        #MODIFY YOUR NUMBERS HERE
    elif line == 'Last':
        inMiddle = false

【讨论】:

    【解决方案4】:

    请原谅我访问文件的方式有点不同

    with open('file.txt') as f:
        file_string = f.read()
    
    middle_to_end = file_string.split('Middle Value\n')[-1]
    just_middle   = middle_to_end.split('Last Value\n')[0]
    
    middle_lines = just_middle.splitlines()
    for line in middle_lines:
        do_something
    

    【讨论】:

    • 没有list.split方法。
    • 谢谢 - 我正在关注其他事情
    • just_middle.split() 在任何空格上拆分,而不仅仅是换行符,因此您将使用'3'5' 等行,而不是' 3 5 6' 之类的行。我假设你的意思是splitlines,所以我修复了它。
    • 同时,我想我会在这里使用partition 而不是split,因为它对错误/边缘情况有什么作用……但实际上,OP 应该弄清楚他想要什么发生错误/边缘情况,然后查看它们各自的作用(可能还将 1 传递给 split),然后选择他想要的。
    【解决方案5】:

    基本上,您正在设置一个标志来表示您在“该部分”中。下面我可以选择在完成时设置一个不同的标志。例如,您可以在 flag 为 2 时退出。

    with open('file.txt') as f, open('out.txt', 'w') as f2:
    
       section = 0;
    
       for line in f:
          if line.startswith("Middle"):
              section = 1
          elif line.startswith("Last"):
              section = 2
    
    
    
          if section == 1:
            #collect digits and output to other file     
            f2.write(line)         
    
          elif section == 2:
             #close file and break out
             f.close()
             f2.close()
             break
          else:
              continue
    

    【讨论】:

    • 你为什么要写if len(line) &gt; 6 and line[:6] == "Middle"?首先,您不需要第一部分,因为line[:6] == "Middle" 对于任何较短的内容都将始终为假。其次,line.startswith("Middle") 更具可读性和健壮性——不必自己计算字符串的长度意味着不会出现错误,因为您计算错误,或者后来更改了一个而不是另一个。
    猜你喜欢
    • 1970-01-01
    • 2020-12-17
    • 2019-12-21
    • 1970-01-01
    • 2021-07-22
    • 1970-01-01
    • 1970-01-01
    • 2021-08-24
    • 2023-03-04
    相关资源
    最近更新 更多