【问题标题】:Python numpy ndarray skipping lines from textPython numpy ndarray 从文本中跳过行
【发布时间】:2016-08-23 19:10:55
【问题描述】:

基于this answer,我使用changethis方法

import numpy as np
import os

def changethis(pos):
    appex = sfile[pos[1]-1][:pos[2]] + '*' + file[pos[1]-1][pos[2]+len(pos[0]):]
    file[pos[1]-1] = appex

pos = ('stack', 3, 16)
sfile = np.genfromtxt('in.cpp',dtype='str',delimiter=os.linesep)
changethis(pos)
print(file)

in.cpp 是一个源文件,其中包含以下内容:

/* Multi-line 
comment
*/

#include <iostream>
#include <fstream>

using namespace std;

int main (int argc, char *argv[]) {
  int linecount = 0;
  double array[1000], sum=0, median=0, add=0;
  string filename;
  if (argc <= 1)
      {
          cout << "Error" << endl;
          return 0;
      }

我得到了输出:

['using namespace std;' 'int main (int argc, char *argv[]) {'
 'int linecount = *' 'double array[1000], sum=0, median=0, add=0;'
 'string filename;' 'if (argc <= 1)' '{' 'cout << "Error" << endl;'
 'return 0;' '}']

请注意,ndarray 中缺少 多行注释include 语句empty-lines 行.

我不明白为什么会发生这种情况,因为 delimiter 被设置为考虑每个换行符。

关于如何输出的任何建议:

['/* Multi-line' 'comment' '*/' '' '#include <iostream>',
 '' '#include <fstream>' '' 'using namespace std;'
 '' 'int main (int argc, char *argv[]) {'
 'int linecount = *' 'double array[1000], sum=0, median=0, add=0;'
 'string filename;' 'if (argc <= 1)' '{' 'cout << "Error" << endl;'
 'return 0;' '}']

【问题讨论】:

  • 无法重现您的错误。我得到所有非空行作为输出
  • 你之前得到的答案很奇怪。 np.genfromtxt 是一个奇怪的、不适合用于此目的的工具。
  • @M.T 我可能在我的问题末尾显示的“理想”输出中弄乱了几个逗号 - 将很快编辑。但是,缺少内容的输出与我在描述中描述的完全一样。
  • @user2357112 可能是这样,但公平地说,它就像我想要的那样工作;也就是说,如果我能让它按照这个问题的要求行事。如果你能提供另一种更合适的方法,那就太好了!
  • 我想你想要空行?

标签: python numpy multidimensional-array


【解决方案1】:

再次抱歉使用genfromtxt,没有理解您的意图,只是试图为问题提供可能的解决方案。作为该特定解决方案的后续行动(已提供其他解决方案),您可以这样做:

import numpy as np
import os

def changethis(pos):
    # Notice file is in global scope
    appex = file[pos[1]-1][:pos[2]] + '*' + file[pos[1]-1][pos[2]+len(pos[0]):]
    file[pos[1]-1] = appex

pos = ('stack', 3, 16)
file = np.array([i for i in open('in.txt','r')]) # instead of genfromtext.
changethis(pos)
print(file)

,导致:

['/* Multi-line \n' 'comment\n' '*/\n*' '\n' '#include <iostream>\n'
 '#include <fstream>\n' '\n' 'using namespace std;\n' '\n'
 'int main (int argc, char *argv[]) {\n' '  int linecount = 0;\n'
 '  double array[1000], sum=0, median=0, add=0;\n' '  string filename;\n'
 '  if (argc <= 1)\n' '      {\n' '          cout << "Error" << endl;\n'
 '          return 0;\n' '      }']

编辑:另一个用户提到的另一个相关点是我用于文件的范围。我并不是要告诉你在全局范围内做事,我的意思是解释该函数正在工作,因为文件在全局范围内。在任何情况下,您都可以创建一个函数来保存范围:

import numpy as np
import os

def changeallthese(poslist,path):
    def changethis(pos):
        appex = file[pos[1]-1][:pos[2]-1] + '*' + file[pos[1]-1][pos[2]-1+len(pos[0]):]
        file[pos[1]-1] = appex
    file = np.array([str(i) for i in open(path,'r')])
    for i in poslist:
        changethis(i)
    return file

poslist = [('stack', 3, 16),('stack', 18, 1),('/* Multi-line', 1, 1)]
file =   changeallthese(poslist,'in.txt')
print(file)

,结果为:

['* \n' 'comment\n' '*/\n*' '\n' '#include <iostream>\n'
 '#include <fstream>\n' '\n' 'using namespace std;\n' '\n'
 'int main (int argc, char *argv[]) {\n' '  int linecount = 0;\n'
 '  double array[1000], sum=0, median=0, add=0;\n' '  string filename;\n'
 '  if (argc <= 1)\n' '      {\n' '          cout << "Error" << endl;\n'
 '          return 0;\n' '* }']

要将数组写入文件,您可以使用 Python 中的普通文件写入系统:

fid = open('out.txt','w')
fid.writelines(file)
fid.close()

,或者使用 numpy 中的函数(但我不确定它是否会添加更多的端线或不那么小心):

np.savetxt('out.txt',file,fmt='%s')

【讨论】:

  • 太棒了!如果我没记错的话,它也是有效的。另外,有没有办法在替换之后将列表的每一行写入相同的文本,即用更改后的字符串版本覆盖旧的in.txt
  • @hask.duk 嗯...,效率取决于标准。此代码非常简单,可以在需要时对其进行更改,并且很少依赖 Python 原生代码。我用保存(覆盖文件)的解决方案编辑了帖子。由于我提到的原因,请注意savetxt 的想法。
  • 为了获得深入的理解,您选择使用 numpy 数组是否有根本原因?
  • @hask.duk 一般来说,例如,numpy 数组远不如列表灵活。但它们往往更快(并且占用更少的内存,虽然我不确定我在引用谁),特别是如果你需要使用它的广播能力。在您的问题中,您似乎对索引进行了很好的控制,那么当可以使用简单的解决方案时,为什么还要构建更大(尽管更灵活)的算法?考虑到您的标准,我只是给出了在我看来更合适的答案(尽管 genfromtxt 是文件阅读器的不幸选择,对此再次感到抱歉)。
【解决方案2】:

如果您想要代表文件行的字符串列表,请打开文件并使用readlines()

with open('in.cpp') as f:
    lines = f.readlines()

# Have changethis take the list of lines as an argument
changethis(lines, pos)

不要使用np.genfromtxt;这是一个表格数据解析器,具有您不想要的各种行为,例如将# 视为行注释标记。

根据您打算如何处理此列表,您甚至可以避免需要明确的行列表。此外,file 是变量名的错误选择(它隐藏了内置的file),changethis 应该真正将列表作为参数而不是全局变量。总的来说,您之前得到的答案非常糟糕。

【讨论】:

  • 感谢您的解释。所有的好点。但是,我主要关心的是如何实现related question 中所述的内容。您能否给我一些代码替代方案,以便使用您建议的readlines 做到这一点?
  • 我非常同意糟糕的命名约定和将列表作为输入,但由于定义了changethis(使用未在函数中定义的变量file),使代码工作的最小更改预期的方式就是我描述的方式。
  • @M.T 我修复了命名约定的问题(它是作为一个粗略的示例编写的)。我看不出带有readlines 的建议代码如何使我能够用相关问题中所述的特定位置替换特定给定字符串。
【解决方案3】:

如果文件不是太大:

import numpy as np
import os

def changethis(linelist,pos):
    appex = linelist[pos[2]-1][:pos[3]] + pos[1] + linelist[pos[2]-1][pos[3]+len(pos[0]):]
    linelist[pos[2]-1] = appex

pos = ('Multi','Three', 1, 3)

with open('in.cpp','r')  as f:
    lines=f.readlines()
    changethis(lines,pos)
print(''.join(lines))

readlines 将您的文件转换为行列表(内存效率低且速度慢,但可以完成工作。如果少于 1k 行应该没问题)。

除了pos 之外,该函数还将行列表作为输入。我还修改了函数,将pos[0] 替换为pos[1],而不是pos[2] 行和字符pos[3] 之后的*

我得到这个作为输出:

/* Three-line 
comment
*/

#include <iostream>
#include <fstream>

using namespace std;

int main (int argc, char *argv[]) {
  int linecount = 0;
  double array[1000], sum=0, median=0, add=0;
  string filename;
  if (argc <= 1)
      {
          cout << "Error" << endl;
          return 0;
      }

【讨论】:

  • 两件事;首先,我很可能会有大文件,所以也许更有效的版本 - 如果你知道 - 会是理想的,其次,我需要能够替换给定单词或短语及其行和列的特定单词或短语数字(即完全按照related question 中所述
  • @hask.duk 我会记住 answer 给你的另一个问题,它处理替换同一行上的多个单词。
猜你喜欢
  • 2011-05-02
  • 1970-01-01
  • 2022-01-01
  • 2018-06-05
  • 1970-01-01
  • 2021-10-15
  • 2018-10-10
  • 2014-02-01
  • 2016-01-31
相关资源
最近更新 更多