【问题标题】:regular expression - incremental replacement正则表达式 - 增量替换
【发布时间】:2011-03-12 06:28:40
【问题描述】:

有没有办法只用正则表达式进行整数增量替换。

这是问题所在,我有一个包含 1 000 000 行的文本文件,所有行都以 % 开头

我想使用正则表达式将 # 替换为整数。

input:

% line one

% line two

% line three

...

output:

1 line one

2 line two

3 line three

...

【问题讨论】:

  • 你为什么只想使用正则表达式?
  • 为什么人们总是认为,一个好的正则表达式可以解决任何问题?对我来说,它们丑得要命,我希望,我永远不需要维护一个......看看这个:stackoverflow.com/questions/1732348/… - 这是黑色艺术。
  • 否 - 正则表达式不会“全部替换”,因此甚至不会进行增量替换
  • @Imre:嗯——你是绝对的。 “正则表达式不会“全部替换””?那是错误的。此外,通过辅助函数,它可以进行增量替换。例如,检查我的答案。

标签: c# java php python regex


【解决方案1】:
n = 1
with open('sourcefile.txt') as input:
    with open('destination.txt', 'w') as output:
        for line in input:
            if line.startswith('%'):
                line = str(n) + line[1:]
                n += 1
            output.write(line)

【讨论】:

    【解决方案2】:

    这是一种在 Python 中实现的方法

    import re
    from itertools import count
    s="""
    % line one
    % line two
    % line three"""
    
    def f():
        n=count(1)
        def inner(m):
            return str(next(n))
        return inner
    
    new_s = re.sub("%",f(),s)
    

    或者,您可以在其中使用 lambda 函数,如下所示:

    new_s = re.sub("%",lambda m,n=count(1):str(next(n)),s)
    

    但是完全跳过正则表达式更容易更好

    from __future__ import print_function   # For Python<3
    import fileinput
    
    f=fileinput.FileInput("file.txt", inplace=1)
    for i,line in enumerate(f):
        print ("{0}{1}".format(i, line[1:]), end="")
    

    由于所有行都以“%”开头,因此甚至不需要查看第一个字符

    【讨论】:

    • @Andreas_D:嗯,他用的是正则表达式。
    • 好的,我添加了一个(更好的)使用 fileinput 的替代方案 :)
    【解决方案3】:

    虽然这个问题最好通过逐行读取文件并使用简单的字符串函数检查第一个字符来解决,但以下是在 java 中对字符串进行增量替换的方法:

    Pattern p = Pattern.compile("^%");
    Matcher m = p.matcher(text);
    StringBuffer sb = new StringBuffer();
    int i = 0;
    while (m.find()) {
        m.appendReplacement(sb, String.valueOf(i++));
    }
    m.appendTail(sb);
    
    return sb.toString();
    

    【讨论】:

    • 您可能想要 ++1,而不是 1++。行号通常从 1 开始。
    • ...或将 i 初始化为 1 而不是 0。
    • 这是我需要的答案,带有正则表达式的答案。
    【解决方案4】:

    在 python re.sub 中接受函数作为参数见http://docs.python.org/library/re.html#re.sub

    【讨论】:

      【解决方案5】:

      根据您选择的语言(您已经列出了一些)PHP 的 preg_replace_callback() 可能是一个合适的函数

      $text = "% First Line\n% Second Line\n% Third Line";
      
      function cb_numbers($matches)
      {
          static $c = 1;
      
          return $c++;
      }
      $text = preg_replace_callback(
                  "/(%)/",
                  "cb_numbers",
                  $text);
      
      echo $text;
      

      【讨论】:

        【解决方案6】:

        这是一个 C# (3.0+) 版本:

        string s = "% line one\n% line two\n% line three";
        int n = 1;
        s = Regex.Replace(s, @"(?m)^%", m => { return n++.ToString(); });
        Console.WriteLine(s);
        

        输出:

        1 line one
        2 line two
        3 line three
        

        当然,它需要将整个文本加载到内存中。如果我真的这样做,我可能会采用逐行方法。

        【讨论】:

          【解决方案7】:

          还有一个很好的 PHP 版本:

          $input = @fopen('input.txt', 'r');
          $output = @fopen("output.txt", "w");
          
          if ($input && $output) {
              $i = 0;
              while (!feof($input)) {
                  $line = fgets($input);
                  fputs($output, ($line[0] === '%') ?
                      substr_replace($line, ++$i, 0, 1) :
                      $line
                  );
              }
              fclose($input);
              fclose($output);
          }
          

          因为你可以,一个 perl 单行(是的,使用正则表达式):

          perl -i.bak -pe 'BEGIN{$i=1} (s/^%/$i/) && $i++' input.txt
          

          【讨论】:

            【解决方案8】:
            import re, itertools
            counter= itertools.count(1)
            replacer= lambda match: "%d" % counter.next()
            text= re.sub("(?m)^%", replacer, text)
            

            counter 是……一个计数器 :)。 replacer 是一个以字符串形式返回计数器值的函数。 "(?m)^%" 正则表达式对于行首的每个 % 都是正确的(注意多行标志)。

            【讨论】:

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