Prolog 文字处理序言
我试图在序言中将一个单词按照两条不同的规则分成不同的音节 规则1:元音辅音元音(在第二个元音后打断单词)Prolog 文字处理序言,prolog,logic,dcg,logical-purity,Prolog,Logic,Dcg,Logical Purity,我试图在序言中将一个单词按照两条不同的规则分成不同的音节 规则1:元音辅音元音(在第二个元音后打断单词) 规则2:元音-辅音-辅音-元音(两个字母之间的分词) 辅音),例如,计算器=计算器 我在Prolog中已经有了下面的代码,但是,它只分析单词的前3或4个字母 我需要它来处理和分析整个单词 vowel(a). vowel(e). vowel(i). vowel(o). vowel(u). consonant(L):- not(vowel(L)
规则2:元音-辅音-辅音-元音(两个字母之间的分词) 辅音),例如,计算器=计算器 我在Prolog中已经有了下面的代码,但是,它只分析单词的前3或4个字母 我需要它来处理和分析整个单词
vowel(a).
vowel(e).
vowel(i).
vowel(o).
vowel(u).
consonant(L):- not(vowel(L)).
syllable(W, S, RW):-
atom_chars(W, [V1, C, V2|Tail]),
vowel(V1),
consonant(C),
vowel(V2),
!,
atomic_list_concat([V1, C, V2], S),
atomic_list_concat(Tail, RW).
syllable(W, S, RW):-
atom_chars(W, [V1, C, C2, V2|Tail]),
vowel(V1),
consonant(C),
consonant(C2),
vowel(V2),
!,
atomic_list_concat([V1, C, C2, V2], S),
atomic_list_concat(Tail, RW).
syllable(W, W, _).
break(W, B):-
syllable(W, B, ''), !.
break(W, B):-
syllable(W, S, RW),
break(RW, B2),
atomic_list_concat([S, '-', B2], B).
我想你可以写得更简单一些。下面是我的实现:
syllable( Input, Final_Word):-
atom_chars( Input, Char_list),
(split(Char_list, Word)-> atom_chars( Final_Word, Word);
Final_Word=Input).
split([],[]).
split([X,Y,Z|T],[X,Y,Z,'-'|T1]):-
vowel(X),vowel(Z),
atom_chars( Input, T),
syllable(Input,T2),
atom_chars( T2, T1).
split([X,Y,Z,W|T],[X,Y,'-',Z|T1]):-
vowel(X),\+vowel(Y),\+vowel(Z),vowel(W),
atom_chars( Input, [W|T]),
syllable(Input,T2),
atom_chars( T2, T1).
split([X|T],[X|T1]):- \+vowel(X),split(T,T1).
split/2拆分单词adding'-',该单词可以按照上述规则添加,并将列表返回到音节atom_chars/2
将列表转换为单词。如果无法拆分单词,则输出为输入
例如:
?- syllable(calculator,L).
L = 'calcu-lato-r'.
我不明白你为什么要写“calculator=calculator”,因为它没有遵循规定的规则,因为“cal”不是元音常量元音,而是元音常量元音常量,并且对其他单词都是一样的…首先,这一设置使得指定字符列表更加方便,如果您经常处理文本,我建议您在代码中使用: 第二,数据,以定义可在所有方向使用的方式表示: vowel(a). vowel(e). vowel(i). vowel(o). vowel(u). consonant(C) :- maplist(dif(C), [a,e,i,o,u]). 现在重点是:由于该程序是完全纯的,并且不会过早错误地提交,因此我们可以使用它来显示还有其他允许的连字号: ?- phrase(word_breaks("calculator"), Hs). Hs = [[c, a, l], [c, u, l, a], [t, o, r]] ; Hs = [[c, a, l], [c, u, l, a, t, o], [r]] ; Hs = [[c, a, l], [c, u, l, a, t, o, r]] ; Hs = [[c, a, l, c, u, l, a], [t, o, r]] ; Hs = [[c, a, l, c, u, l, a, t, o], [r]] ; Hs = [[c, a, l, c, u, l, a, t, o, r]]. -短语(单词“计算器”),Hs)。 Hs=[[c,a,l],[c,u,l,a],[t,o,r]; Hs=[[c,a,l],[c,u,l,a,t,o],[r]; Hs=[[c,a,l],[c,u,l,a,t,o,r]; Hs=[[c,a,l,c,u,l,a],[t,o,r]; Hs=[[c,a,l,c,u,l,a,t,o],[r]]; Hs=[[c,a,l,c,u,l,a,t,o,r]]。
在Prolog中,最好保留代码的通用性,这样您就可以随时观察其他解决方案。请参阅。我想是时候采用DCG后推解决方案了。在break//1的第二个规则中使用了push-back。这是为了反映我们看了四个字符,但只使用了两个字符:
vowel(a). vowel(e). vowel(i). vowel(o). vowel(u).
consonant(C) :- \+ vowel(C).
break([V1,C,V2]) -->
[V1,C,V2],
{vowel(V1), consonant(C), vowel(V2)}.
break([V1,C1]), [C2,V2] -->
[V1,C1,C2,V2],
{vowel(V1), consonant(C1), consonant(C2), vowel(V2)}.
syllables([L|R]) --> break(L), !, syllables(R).
syllables([[C|L]|R]) --> [C], syllables([L|R]).
syllables([[]]) --> [].
因此,整个解决方案不需要一些额外的谓词,例如append/3或reverse/2。我们还对搜索进行了删减,这是因为音节/1的第二条规则中有catchall字符
以下是一些运行示例:
Jekejeke Prolog 2, Laufzeitbibliothek 1.1.6
(c) 1985-2016, XLOG Technologies GmbH, Schweiz
?- set_prolog_flag(double_quotes, chars).
Ja
?- phrase(syllables(R), "calculator").
R = [[c,a,l],[c,u,l,a],[t,o,r]] ;
Nein
?- phrase(syllables(R), "kitchensink").
R = [[k,i,t,c,h,e,n],[s,i,n,k]] ;
Nein
注:在一些较旧的标准草案中,这种DCG技术是
被称为“右手语境”,而不是动词“推”
“后退”,使用动词“前缀”。在较新的标准草案中
这被称为“文本”,而不是动词“推回”,
使用动词“恢复”
如何将“calculato-r”作为一个可接受的连字号?@Boris:根据第一条规则:“元音-辅音-元音(在第二个元音之后打断)”:
ato
:元音-辅音-元音,所以在“o”之后,我们打断!附言:这些规则不是我定的,听起来不对。我很确定这些规则是用来分解成音节的:你不能在末尾留下一个非音节,对吗?而且,只有一种方法(而且应该是!)可以拆分成音节(或者选择可能的连字符点)。或者我不知怎么搞糊涂了?@Boris:不幸的是,我无法回答你的问题,但我绝对认为这是Prolog的一个优点,因为它可以很容易地用来表明,正如你正确指出的那样,光是规定的规则就会导致歧义甚至无效的连字号。使用不纯谓词只会掩盖规则本身的固有问题。我发布我的解决方案主要是为了展示Prolog的这一优势。许多“罗马数字”的例子也是如此:所述的大多数规则都是模棱两可的,但过早地提交隐藏了这一固有问题。我认为我们可以用Prolog检测到这一点很好!不要低估断字的“规则性”!TeXbook包含了一个关于这个主题的重要章节,并指向了一些非常令人惊讶的研究论文,这些论文展示了基于规则的连字号实际上是如何跨不同语言的。这种情况下的数据库主要是规则异常数据库。。。如果有两条规则足以捕捉所有有效的连字号模式,我会感到惊讶。“cal”不是元音辅音元音,但“alcu”是元音辅音元音…没错,所以它能识别“alcu”,并在“alcu”后面加一个“-”,很清楚他是否想在“alcu”之前加“-”如果这就是你的意思…所以我不太确定正确的输出是什么样子…应该是'c-alcu-l-ato-r'?@编码器这真的很有帮助,但正如mat所说,alcu是一个元音常量元音,因为规则表明它必须在两个常量之间断开,计算器应该是计算器。。“al”和“cu”(元音常量元音..常量元音之间的拆分)和“ula”(元音常量元音..第二个元音之后的拆分)之间的一次拆分编辑了答案,尽管我不理解您的标准,因为例如,您可以使用cal-cul-ato-r,因为“ato”是有效的…它是“辅音”,而不是“constant”我刚注意到你在代码中拼写正确,但在文本中没有…这很奇怪,因为辅音不是常量。它们都表示不同的意思,尤其是“constant”“是计算机科学中非常常见的术语。至于代码与文本,这可能意味着你从没有归属的人那里复制了代码(“我已经有代码了”,嗯),这是剽窃,这不好。基本上,据我所知,你正在使用Stackoverflow作为免费的家庭作业写作服务,并取得了一些成功。我对此无能为力,只能告诉你我注意到了。这里的问题和答案代码来自哪里:现在至少它被列为“链接”,其他人也可以看到它
% rule 1: vowel-consonant-vowel (break after second vowel)
rule([V1,C,V2|Rest], Bs0, Bs, Rest) :-
vowel(V1), consonant(C), vowel(V2),
reverse([V2,C,V1|Bs0], Bs).
% rule 2: vowel-consonant-consonant-vowel (break between the consonants)
rule([V1,C1,C2,V2|Rest], Bs0, Bs, [C2,V2|Rest]) :-
vowel(V1), consonant(C1), consonant(C2), vowel(V2),
reverse([C1,V1|Bs0], Bs).
% alternative: no break at this position
rule([L|Ls], Bs0, Bs, Rest) :-
rule(Ls, [L|Bs0], Bs, Rest).
word_breaks([]) --> [].
word_breaks([L|Ls]) --> [Bs],
{ rule([L|Ls], [], Bs, Rest) },
word_breaks(Rest).
word_breaks([L|Ls]) --> [[L|Ls]].
?- phrase(word_breaks("calculator"), Hs).
Hs = [[c, a, l], [c, u, l, a], [t, o, r]] ;
Hs = [[c, a, l], [c, u, l, a, t, o], [r]] ;
Hs = [[c, a, l], [c, u, l, a, t, o, r]] ;
Hs = [[c, a, l, c, u, l, a], [t, o, r]] ;
Hs = [[c, a, l, c, u, l, a, t, o], [r]] ;
Hs = [[c, a, l, c, u, l, a, t, o, r]].
vowel(a). vowel(e). vowel(i). vowel(o). vowel(u).
consonant(C) :- \+ vowel(C).
break([V1,C,V2]) -->
[V1,C,V2],
{vowel(V1), consonant(C), vowel(V2)}.
break([V1,C1]), [C2,V2] -->
[V1,C1,C2,V2],
{vowel(V1), consonant(C1), consonant(C2), vowel(V2)}.
syllables([L|R]) --> break(L), !, syllables(R).
syllables([[C|L]|R]) --> [C], syllables([L|R]).
syllables([[]]) --> [].
Jekejeke Prolog 2, Laufzeitbibliothek 1.1.6
(c) 1985-2016, XLOG Technologies GmbH, Schweiz
?- set_prolog_flag(double_quotes, chars).
Ja
?- phrase(syllables(R), "calculator").
R = [[c,a,l],[c,u,l,a],[t,o,r]] ;
Nein
?- phrase(syllables(R), "kitchensink").
R = [[k,i,t,c,h,e,n],[s,i,n,k]] ;
Nein