如何在Matlab中使用regexprep用不同的值替换文本中的许多匹配项

时间:2018-08-22 15:01:16

标签: regex matlab

我正在Matlab中使用函数regexprep用单元格数组中的值列表替换模式的几个实例。这个想法是用第一个值替换第一个匹配项,用下一个替换第二个匹配项,依此类推。因此,每个匹配项都替换为单元格数组中的 different 值。

documentation中我读到:

  

如果replace是N个字符向量的单元格数组,而expression是单个字符向量,则regexprep会尝试N个匹配项和替换项。

这是我所执行任务的一个示例(对于此示例,假设我知道只有4个匹配项):

% some text:
str = 'abc s;dlf kudnbv. soergi; abcva/.lge roins.br oianabca/ sergosr toibnsabc';
pattern = '([a][b][c])'; % the patern to match
values = {'111','222','333','444'}; % the cell array 
new_str = regexprep(str,pattern,values) % the actual raplace

结果:

new_str =
    '111 s;dlf kudnbv. soergi; 111va/.lge roins.br oian111a/ sergosr toibns111'

当然,此结果是不正确的,因为所有匹配项都被替换为单元格数组中的第一个值。

因此,我搜索了这个问题并找到了explanation。显然,函数regexprep一次执行一次替换,因此在第一次替换之后,找到的第一个匹配项就是最初的第二个匹配项,并且由于它被识别为第一个匹配项,因此被替换为单元格数组中的第一个值(111)。

我可以通过循环来解决此问题,该循环每次以不同的值执行此任务:

new_str = str;
for k = 1:numel(values)
    new_str = regexprep(new_str,pattern,values(k),'once'); % raplace one value each time
end

结果:

new_str =
    '111 s;dlf kudnbv. soergi; 222va/.lge roins.br oian333a/ sergosr toibns444'

这正是我想要的。

我的问题是如何编写pattern或使用regexprep才能获得无循环的相同结果?
在我看来,我对如何使用此功能有些怀念。我还要补充一点,我的真正问题是文本中有100多个匹配项,因此,实际上不能使用([a][b][c])(.*)([a][b][c])(.*)([a][b][c])(.*)([a][b][c])这样的模式和111$2222$4333$6444这样的替换模式(在此处给出正确的结果)

任何帮助将不胜感激!

3 个答案:

答案 0 :(得分:4)

您可以制作一个基本的辅助字符串生成器,并使用命令执行替换令牌。

例如:

classdef strgenerator < handle
    properties
        strs
        ii = 1
    end

    methods
        function self = strgenerator(strs)
            self.strs = strs;
        end

        function outstr = nextstr(self)
            outstr = self.strs{self.ii};

            self.ii = self.ii + 1;
            if self.ii > numel(self.strs)
                self.ii = 1;
            end
        end
    end
end

str = 'abc s;dlf kudnbv. soergi; abcva/.lge roins.br oianabca/ sergosr toibnsabc';
pattern = '([a][b][c])'; % the patern to match
values = strgenerator({'111','222','333','444'}); % the cell array 
new_str = regexprep(str,pattern,'${values.nextstr()}') % the actual raplace

为我们提供:

>> SOcode

new_str =

    '111 s;dlf kudnbv. soergi; 222va/.lge roins.br oian333a/ sergosr toibns444'

答案 1 :(得分:3)

根据问题中链接的文档regexprep(str,pattern,values),其中values是字符串的单元格数组,而pattern是单个字符串,则应用搜索并为{中的每个元素替换一次{1}}。因此,它等效于:

values

在第一次替换之后,str = regexprep(str,pattern,values{1}); str = regexprep(str,pattern,values{2}); str = regexprep(str,pattern,values{3}); ... etc. 中不再存在pattern,因此第二次(及后续)替换找不到任何匹配项。也就是说,每次调用str都会替换所有匹配项。相反,regexprep仅替换第一个匹配项。

因此:

regexprep(...,'once')

将完全按照期望进行操作:

str = 'abc s;dlf kudnbv. soergi; abcva/.lge roins.br oianabca/ sergosr toibnsabc abc/abc';
pattern = '([a][b][c])'; % the patern to match
values = {'111','222','333','444'};
new_str = regexprep(str,pattern,values,'once')

请注意,我在字符串的末尾添加了两个“ abc”元素,并注意这些元素并未被替换。 new_str = '111 s;dlf kudnbv. soergi; 222va/.lge roins.br oian333a/ sergosr toibns444 abc/abc' 有4个元素,则仅替换前4个匹配项。

答案 2 :(得分:2)

我使用@excaza的想法,为在Matlab中不真正使用OOP的人们(像我一样)编写了一个更简单的实现:

我们从一个辅助函数开始,该函数会记住上次调用该函数的索引,并从其输入strCellArray返回下一个单元格:

function out = nextStr(strCellArray)
persistent n
    if isempty(n) || n>numel(strCellArray)
        n = 1;
    end
    out = strCellArray{n};
    n = n+1;
end

然后我们可以写:

values = {'111','222','333','444'}; % the cell array 
new_str = regexprep(str,pattern,'${nextStr(values)}'); % execute the command between {...} on every call to the function
clear nextStr % to reset the counter in the function

并获得相同的结果:

111 s;dlf kudnbv. soergi; 222va/.lge roins.br oian333a/ sergosr toibns444

这里棘手的事情是要注意,尽管我们只调用一次regexprep,但实际上它被连续调用了N次,因此最后一个参数中的命令被评估了N次。