【问题标题】:Insert a newline character every 64 characters using Python使用 Python 每 64 个字符插入一个换行符
【发布时间】:2011-02-09 02:30:42
【问题描述】:

使用 Python,我需要每 64 个字符在字符串中插入一个换行符。在 Perl 中很简单:

s/(.{64})/$1\n/

如何在 Python 中使用正则表达式来做到这一点? 有没有更pythonic的方式来做到这一点?

【问题讨论】:

    标签: regex python


    【解决方案1】:

    我会选择:

    import textwrap
    s = "0123456789"*100
    print('\n'.join(textwrap.wrap(s, 64)))
    

    【讨论】:

    • textwrap 可以感知空间,因此无法正确处理 "12345 "*100
    【解决方案2】:

    @J.F. Sebastiansolution 更进一步(这几乎犯罪!:-)):

    import textwrap
    s = "0123456789"*100
    print textwrap.fill(s, 64)
    

    看,马...没有正则表达式!因为如你所知...http://regex.info/blog/2006-09-15/247

    感谢您向我们介绍textwrap 模块...虽然它从 2.3 开始就在 Python 中,但直到现在我才意识到它(是的,我会公开承认)!!

    【讨论】:

    • textwrap 可以感知空间,因此无法正确处理 "12345 "*100
    【解决方案3】:

    itertools 有一个很好的函数 grouper 对此很有用,特别是如果您的最终切片少于 64 个字符并且您不希望切片错误:

    def grouper(iterable, n, fillvalue=None):
        "Collect data into fixed-length chunks or blocks"
        # grouper('ABCDEFG', 3, 'x') --> ABC DEF Gxx
        args = [iter(iterable)] * n
        return izip_longest(fillvalue=fillvalue, *args)
    

    这样使用:

    big_string = <YOUR BIG STRING>
    output = '\n'.join(''.join(chunk) for chunk in grouper(big_string, 64))
    

    【讨论】:

      【解决方案4】:

      与 Perl 中的相同,但使用反斜杠而不是用于访问组的美元:

      s = "0123456789"*100 # test string
      import re
      print re.sub("(.{64})", "\\1\n", s, 0, re.DOTALL)
      

      re.DOTALL 等价于 Perl 的 s/ 选项。

      【讨论】:

      • QUERY: 如果源字符串是 s2="0123456789"*200 ,您的解决方案似乎被破坏了,only 恰好插入了 16 个 '\n' (在 Python 2.7.1 上)。有什么办法吗?
      • 不错的发现。问题是在搜索字符串和标志之间还有另一个参数“count”(re.DOTALL)。由于我忘记了那个参数,所以 re.DOTALL(值 16)被用作替换的最大数量。
      • @AndiDog:有没有办法使用变量代替64
      • 好吧,只需插入您的号码而不是 64 吗?!
      • 我认为@Forethinker 的意思是“使用变量”,而不是“使用不同的常量”。 "(.{%d})"%varname 似乎有点骇人听闻;一定有更好的办法。
      【解决方案5】:

      没有正则表达式:

      def insert_newlines(string, every=64):
          lines = []
          for i in xrange(0, len(string), every):
              lines.append(string[i:i+every])
          return '\n'.join(lines)
      

      较短但可读性较差(imo):

      def insert_newlines(string, every=64):
          return '\n'.join(string[i:i+every] for i in xrange(0, len(string), every))
      

      以上代码适用于 Python 2.x。对于 Python 3.x,您要使用 range 而不是 xrange

      def insert_newlines(string, every=64):
          lines = []
          for i in range(0, len(string), every):
              lines.append(string[i:i+every])
          return '\n'.join(lines)
      
      def insert_newlines(string, every=64):
          return '\n'.join(string[i:i+every] for i in range(0, len(string), every))
      

      【讨论】:

      • 这个解决方案快了一个数量级。 timeit.timeit 表示执行 100000 次正则表达式解决方案需要 27.8 秒,而执行 100000 次较短的解决方案需要 4.45 秒)。
      • 我还要说,较短的版本是“最 Pythonic”的版本:单行,非常优雅,使用生成器和 join 方法。
      【解决方案6】:

      我建议以下方法:

      "\n".join(re.findall("(?s).{,64}", s))[:-1]
      

      这或多或少是利用 RE 引擎进行循环的非 RE 方法。

      在我作为家庭服务器的一台非常慢的计算机上,这给出了:

      $ python -m timeit -s 's="0123456789"*100; import re' '"\n".join(re.findall("(?s).{,64}", s))[:-1]'
      10000 loops, best of 3: 130 usec per loop
      

      AndiDog的方法:

      $ python -m timeit -s "s='0123456789'*100; import re" 're.sub("(?s)(.{64})", r"\1\n", s)'
      1000 loops, best of 3: 800 usec per loop
      

      gurney alex 的第二个/Michael 的方法:

      $ python -m timeit -s "s='0123456789'*100" '"\n".join(s[i:i+64] for i in xrange(0, len(s), 64))'
      10000 loops, best of 3: 148 usec per loop
      

      我不认为textwrap 方法对于问题的规范是正确的,所以我不会计时。

      编辑

      因为不正确而更改了答案(真丢脸!)

      编辑 2

      只是为了好玩,使用itertools的无RE方法。它在速度上排名第三,而且它不是 Pythonic(太 lispy):

      "\n".join(
         it.imap(
           s.__getitem__,
           it.imap(
             slice,
             xrange(0, len(s), 64),
             xrange(64, len(s)+1, 64)
           )
         )
       )
      
      $ python -m timeit -s 's="0123456789"*100; import itertools as it' '"\n".join(it.imap(s.__getitem__, it.imap(slice, xrange(0, len(s), 64), xrange(64, len(s)+1, 64))))'
      10000 loops, best of 3: 182 usec per loop
      

      【讨论】:

      • 这似乎无法正常工作。如果您输入的字符数超过 64 个,则会在每个字符后输出换行符,而不是在每 64 个字符后输出一个换行符。
      • 点对点,biffabacon。修好了。
      【解决方案7】:

      很小,不太好:

      "".join(s[i:i+64] + "\n" for i in xrange(0,len(s),64))
      

      【讨论】:

        猜你喜欢
        • 2019-04-09
        • 1970-01-01
        • 1970-01-01
        • 2017-03-25
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多