从文本文件中提取特定数据

4

我有一个txt文件,在notepad++中看起来像这样:

/a/apple 1
/b/bat 10
/c/cat 22
/d/dog 33
/h/human/female 34

现在我想提取末尾数字之前第二个斜杠后的所有内容。所以我想要的输出是:
out = {'apple'; 'bat'; 'cat'; 'dog'; 'human/female'}

我写了这段代码:
file= fopen('file.txt');
out=  textscan(file,'%s','Delimiter','\n');
fclose(file);

它给出:

out =
   {365×1 cell}

out{1} = 

    '/a/apple 1'
    '/b/bat 10'
    '/c/cat 22'
    '/d/dog 33'
    '/h/human/female 34'

如何从文本文件中获取所需的输出(如果可能直接获取)?如果不能直接获取所需的输出,是否有任何正则表达式可用?


你告诉Matlab分隔符是换行符'\n'。你尝试过用斜杠'/'替换它吗? - Flynn
是的,它会搞乱一切。它会给出:{'';'a';'apple'.....}我有多行以/a/开头,所以我无法使用索引跳过,因为没有模式。 - Likeunknown
如果你总是想要第三个单词...你可以通过索引直接捕获它,不是吗? - Flynn
不总是第三个单词。我想要第二个斜杠后但数字前的所有内容。为了澄清,我添加了另一个示例。 - Likeunknown
3个回答

4

您可以直接从textscan获得所需的输出,无需进行进一步处理:

file = fopen('file.txt');
out = textscan(file, '/%c/%s %d');
fclose(file);
out = out{2}

out =

  5×1 cell array

    'apple'
    'bat'
    'cat'
    'dog'
    'human/female'

请注意,格式说明符字符串中的两个斜杠将被视为输出中要忽略的文字。任何其他斜杠都将被捕获到字符串 (%s) 中。此外,不需要指定 分隔符参数,因为默认分隔符是空格,所以尾数将被捕获为单独的数字值 (%d)。

3
另一种选择是使用正则表达式,利用您已经创建的字符串单元数组,但巧妙地根据您想要在单元数组中的每个字符串中搜索的指定输入模式来提取所需内容。在MATLAB中使用regexp函数来实现:
% Your code
file= fopen('file.txt');
out =  textscan(file,'%s','Delimiter','\n');
fclose(file);

% Proposed changes
out = regexp(out{1}, '/\w*/(.+)\s', 'tokens', 'once');
out = [out{:}].';

请注意,textscan将返回一个单元格数组的单个元素,因此在使用 regexp 之前需要通过访问第一个元素来解压缩单元格。 所提出的代码所做的是对于单元格数组中的每个字符串,它搜索相应的组合:
  1. / - 首先查找开始正斜杠

  2. \w*/ - 然后查找字母或数字字符 - 在遇到另一个斜线之前至少有一个这些字符。 其好处在于您不仅限于第一个斜杠后的一个字符。 它们可以是任何字母数字字符。

  3. (.+) - 指定一个,在第二个斜杠之后,我们收集空格之前的所有字符(见下一点)。 之所以要查找所有字符而不仅仅是字母数字,是因为可能还会出现更多的斜杠。 我们只有在遇到空格时才停止搜索(同样见下一点)。

  4. \s - 查找空格

它将搜索特定的字符集,实际上是在遇到空格之前的文本。 请注意,我必须在组(.+)之后用空格进行分隔,否则它基本上会返回第二个斜杠后的整行文本。 您需要在那里使用它来限制字符串内的搜索。

第3点中的()很重要,因为regexp中的'tokens'属性允许您另外提取位于组中的字符串。 使用'once'仅提取第一个匹配项。 请注意,输出将是嵌套的单元格数组,其中每个单元格都是表示组内匹配的一个元素。 我们可以使用逗号分隔的列表解压缩单元格,并将它们全部连接到单个单元格数组中。 我们转置以保持您想要的列形矢量。

这样做后,我们得到以下结果:

>> out

out =

  5×1 cell array

    'apple'
    'bat'
    'cat'
    'dog'
    'human/female'

然而,我认为你更关心内容而不是数据形式,因此如果您愿意,可以删除转置。这种方法的好处在于无需使用cellfun,因为regexp会隐式循环。


我的问题中有一个小错误,但它不会对你的答案产生太大影响。实际上是 out{1}。谢谢。你的答案可行。 - Likeunknown
1
@Likeunknown 我明白了。我只需要再解压一次单元格。我会编辑我的帖子。 - rayryeng

1

你已经快到了。

file = fopen('file.txt');
out = textscan(file, '%s', 'Delimiter', '\n');
parsed = cellfun(@(x) textscan(x, '/%c/%s %d'), out{1}, 'uniformoutput', false);
parsed = cellfun(@(x) x{2}, parsed, 'uniformoutput', false);
fclose(file);

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接