在列表列表中删除标点符号的问题

Problems with deleting punctuation in list of lists

我正在尝试编写序言代码,该代码将从列表列表中的所有列表中删除所有标点符号(.,!? 等)。这是我目前所拥有的:

delete_punctuation(_,[],_).
delete_punctuation(Character,[List|Tail],Resultlist) :- 
    delete(List,Character,NewList),
    delete_punctuation(Character,Tail,[NewList|Resultlist]).

而 'Character' 将为 33!或 46 为 。依此类推,因为我将仅在字符代码列表中使用它。 (我知道,该函数实际上适用于我也想从列表中删除的其他元素。)

我询问时得到的结果:

delete_punctuation(33,[[45,33,6],[4,55,33]],X).

只是

|: true.

但是,我希望它是:

|: X = [[45,6],[4,55]].

我需要改进什么?

对于这个问题,我会通过分别解决两个子问题来解决它,即:

  • Filter/exclude 单个列表中的字符代码;
  • 将上述解决方案应用于字符代码列表列表。

为此,我会这样处理:

exclude2(_, [], []).
exclude2(Code, [Code|Xs], Ys) :-
  !, % ignore the next clause if codes match
  exclude2(Code, Xs, Ys).
exclude2(Code, [X|Xs], [X|Ys]) :-
  % else, Code != X here
  exclude2(Code, Xs, Ys).

请注意,某些实现如 SWI-Prolog provide exclude/3 as a built-in,因此您实际上可能不需要自己定义它。

现在,将上述谓词应用于列表的列表:

delete_punctuation(_, [], []).
delete_punctuation(Code, [L|Ls], [NewL|NewLs]) :-
  exclude(Code, L, NewL),
  delete_punctuation(Code, Ls, NewLs).

然而,同样,根据实现的不同,可以使用像 maplist/3 这样的内置函数来实现相同的效果,而无需定义新的谓词:

?- maplist(exclude2(33), [[45,33,6],[4,55,33]], X).
X = [[45, 6], [4, 55]] ;
false.

n.b。如果您想使用所有 SWI 内置函数,exclude/3 需要将测试作为目标,如下所示:

?- maplist(exclude(==(33)), [[45,33,6],[4,55,33]], X).
X = [[45, 6], [4, 55]] ;
false.

对于更通用的方法,您甚至可以将要排除的所有代码(例如任何和所有标点字符代码)添加到列表中以用作过滤器:

excludeAll(_, [], []).
excludeAll(Codes, [Code|Xs], Ys) :-
  member(Code, Codes),
  !,
  excludeAll(Codes, Xs, Ys).
excludeAll(Codes, [X|Xs], [X|Ys]) :-
  excludeAll(Codes, Xs, Ys).

然后您可以添加一个列表,其中包含要删除的所有代码:

?- maplist(excludeAll([33,63]), [[45,33,6],[4,55,33,63]], X).
X = [[45, 6], [4, 55]] ;
false.