【问题标题】:Check if string is substring in Prolog检查字符串是否是Prolog中的子字符串
【发布时间】:2013-12-13 13:36:04
【问题描述】:

有没有办法在 Prolog 中检查一个字符串是否是另一个字符串的子字符串?我尝试将字符串转换为字符列表,然后检查第一组是否是第二组的子集,这似乎不够严格。这是我当前的代码:

isSubstring(X,Y):-
        stringToLower(X,XLower),
        stringToLower(Y,YLower),
        isSubset(XLower,YLower).

isSubset([],_).
isSubset([H|T],Y):-
        member(H,Y),
        select(H,Y,Z),
        isSubset(T,Z).

stringToLower([],[]).
stringToLower([Char1|Rest1],[Char2|Rest2]):-
        char_type(Char2,to_lower(Char1)),
        stringToLower(Rest1,Rest2).

如果我用这个来测试

isSubstring("test","tesZting").

它返回yes,但应该返回no。

【问题讨论】:

  • 子列表算法应该满足 - 你能举一个你的字符列表子集算法的例子和导致它失败的输入吗?
  • 我刚刚编辑了问题并添加了代码和示例。
  • 我不确定,但你想要的是一个子序列。见en.wikipedia.org/wiki/Substring
  • 我的意思是Java中的字符串。

标签: prolog substring dcg subsequence


【解决方案1】:

不清楚你所说的字符串是什么意思。但是,既然您说要将其转换为列表,则可能是指原子。为此,ISO Prolog 提供了atom_concat/3sub_atom/5

| ?- atom_concat(X,Y,'abc').
  X = '', Y = abc
; X = a, Y = bc
; X = ab, Y = c
; X = abc, Y = ''.

| ?- sub_atom('abcbcbe',Before,Length,After,'bcb').
  Before = 1, Length = 3, After = 3
; Before = 3, Length = 3, After = 1.

否则,请使用 DCG!方法如下

seq([]) --> [].
seq([E|Es]) --> [E], seq(Es).

... --> [] | [_], ... .

subseq([]) --> [].
subseq(Es) --> [_], subseq(Es).
subseq([E|Es]) --> [E], subseq(Es).

seq_substring(S, Sub) :-
   phrase((...,seq(Sub),...),S).

seq_subseq(S, Sub) :-
   phrase(subseq(Sub),S).

致谢

上述...的定义第一次出现在p。 205,注释 1 的

David B. Searls,用定从句语法研究 DNA 的语言学。 NACLP 1989,第 1 卷。

【讨论】:

    【解决方案2】:

    Prolog 字符串是列表,其中列表的每个元素都是表示相关字符代码点的整数值。字符串"abc" 与列表[97,98,99]完全等效(假设您的prolog 实现使用Unicode 或ASCII,否则值可能不同)。这导致了这个(从 Big-O 的角度来看可能是次优的)解决方案,它基本上说 X 是 S 的子字符串,如果

    • S 有一个后缀 T,这样,并且
    • X 是 T 的前缀

    代码如下:

    substring(X,S) :-
      append(_,T,S) ,
      append(X,_,T) ,
      X \= []
      .
    

    我们将 X 限制为不是空列表(又名 nil 字符串 ""),因为从概念上讲,可以在任何字符串中找到大量零长度子字符串:长度为 n 有 2+(n-1) 个 nil 子字符串,在字符串中的每个字符之间一个,一个在第一个字符之前,一个在最后一个字符之后。

    【讨论】:

      【解决方案3】:

      问题在于您的isSubset/2
      您试图在一个谓词中捕捉两种不同的情况。您正在寻找第一个位置来尝试匹配您的子字符串,或者您已经找到该点并正在检查字符串是否“对齐”。

      isSubset([], _).
      isSubSet(Substring, String) :-
          findStart(Substring, String, RestString),
          line_up(Substring, RestString).
      
      findStart([], String, String).
      findStart([H|T], [H|T1], [H|T1]).
      findStart(Substring, [_|T], RestString) :-
          findStart(Substring, T, RestString).
      
      line_up([], _).
      line_up([H|T], [H|T1]) :-
          line_up(T, T1).
      

      可以将这些组合成一个谓词,如下所示:

      isSublist([], L, L).
      isSublist([H|T], [H|T1], [H|T1]) :-
          isSublist(T, T1, T1).
      isSublist(L, [_|T], Rest) :-
          isSublist(L, T, Rest).
      

      【讨论】:

        【解决方案4】:

        使用 DCG,您可以执行以下操作:(SWI)

        %                   anything  substring anything
        substr(String) --> ([_|_];[]), String,  ([_|_];[]).
        
        % is X a substring of Y ?
        substring(X,Y) :- phrase(substr(X),Y).
        

        【讨论】:

        • 由于 B、GNU、SICStus、Ciao 和当前 DCG 草案中的 [_|_],这被拒绝了。似乎只有 SWI 和 YAP 允许这样做。
        • 好的,我将添加该注释。谢谢@false。
        猜你喜欢
        • 2011-11-09
        • 2013-05-18
        • 1970-01-01
        • 2011-02-07
        • 1970-01-01
        • 2019-05-11
        • 2013-04-29
        • 2021-12-20
        相关资源
        最近更新 更多