【问题标题】:multi string search and replace多字符串搜索和替换
【发布时间】:2018-01-02 02:10:26
【问题描述】:

我有 2 个文本文件

File1 有超过 400K 行。每一行都与此示例相似:

hstor,table,"8bit string",ABCD,0000,0,4,19000101,today

File2 有一个新的 8 位字符串列表,用于替换 file1 中的当前字符串,同时保留 file1 中的其余部分。

所以 file1 来自

hstor,table,"OLD 8bit string",ABCD,0000,0,4,19000101,today

hstor,table,"NEW 8bit string",ABCD,0000,0,4,19000101,today

我不能 sed 400K 次

如何编写脚本,以便将 file1 中的所有 OLD 8bit 字符串替换为 file2 中列出的 NEW 8bit 字符串?

【问题讨论】:

  • 您尝试过什么了吗?您目前的研究工作是什么?你觉得卡在哪里? :) 对于未来:请尽量考虑使用正确的标点符号。它使您的问题更具可读性。
  • 您可以使用join 命令来解决您的问题。 man join 是你的朋友。
  • “我不能 sed 400K 次” - 为什么?

标签: bash search awk sed replace


【解决方案1】:

如果您需要多次执行此操作并且性能很重要,我用 C 编写了一个程序来执行此操作。这是this code 的修改版本。我知道您没有使用任何 C 标记,但我的印象是您主要关心的是完成工作。

注意:

我对此不承担任何责任。这是一个相当快速的破解,我确实假设了一些东西。一种假设是您要替换的字符串不包含任何逗号。另一个是没有行长于 100 字节。第三个假设是输入文件分别命名为filerep。如果您想尝试一下,请确保事后检查数据。它写入标准输出,因此您只需将输出重定向到新文件。它在大约两秒钟内完成这项工作。

代码如下:

#include <stdio.h>
#include <stdlib.h>
#include <memory.h>

int main()
{

  /* declare a file pointer */
  FILE    *infile;
  FILE    *replace;
  char    *buffer;
  char    *rep_buffer;
  long    numbytes;
  long    rep_numbytes;

  /* open an existing file for reading */
  infile = fopen("file", "r");
  replace = fopen("rep", "r");

  /* quit if the file does not exist */
  if(infile == NULL)
    return 1;
  if(replace == NULL)
    return 1;

  /* Get the number of bytes */
  fseek(infile, 0L, SEEK_END);
  numbytes = ftell(infile);
  fseek(replace, 0L, SEEK_END);
  rep_numbytes = ftell(replace);

  /* reset the file position indicator to
     the beginning of the file */
  fseek(infile, 0L, SEEK_SET);
  fseek(replace, 0L, SEEK_SET);

  /* grab sufficient memory for the
     buffer to hold the text */
  buffer = (char*)calloc(numbytes, sizeof(char));
  rep_buffer = (char*)calloc(rep_numbytes, sizeof(char));

  /* memory error */
  if(buffer == NULL)
    return 1;
  if(rep_buffer == NULL)
    return 1;

  /* copy all the text into the buffer */
  fread(buffer, sizeof(char), numbytes, infile);
  fclose(infile);
  fread(rep_buffer, sizeof(char), rep_numbytes, replace);
  fclose(replace);


  char line[100]={0};
  char *i=buffer;
  char *r=rep_buffer;

  while(i<&buffer[numbytes-1]) {
    int n;

    /* Copy from infile until second comma */
    for(n=0; i[n]!=','; n++);
    n++;
    for(; i[n]!=','; n++);
    n++;
    memcpy(line, i, n);

    /* Copy a line from replacement */
    int m;
    for(m=0; r[m]!='\n'; m++);

    memcpy(&line[n], r, m);

    /* Skip corresponding text from infile */
    int k;
    for(k=n; i[k]!=','; k++);

    /* Copy the rest of the line */
    int l;
    for(l=k; i[l]!='\n'; l++);
    memcpy(&line[n+m], &i[k], l-k);

    /* Next line */
    i+=l;
    r+=m+1;

    /* Print to stdout */
    printf("%s", line);
  }    


  /* free the memory we used for the buffer */
  free(buffer);
  free(rep_buffer);
} 

【讨论】:

    【解决方案2】:

    这可能对你有用(GNU sed):

    sed 's#.*#s/[^,]*/&/3#' file2 | cat -n | sed -f - file1
    

    这会将 file2 转换为 sed 脚本文件,然后在 file1 上运行它。

    第一个 sed 脚本获取 file2 中的每一行并将其更改为替换命令,该命令将目标中的第三个字段替换为 file2 当前行的内容。

    这被传送到cat 命令中,该命令插入行号,sed 脚本将使用这些行号来处理每个替换命令。

    最后的 sed 命令使用 /dev/stdin 读取 sed 脚本并针对输入文件 file1 运行它。

    【讨论】:

    • 似乎有效。但是,完成 10% 需要 20 分钟,所以如果这是 OP 必须多次执行的操作,我可以理解是否需要很长时间。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-10-03
    • 1970-01-01
    • 2010-11-14
    • 2015-11-13
    • 2010-09-10
    相关资源
    最近更新 更多