我在库中找到一个谓词xml_quote_attribute / 2(sgml) SWI-Prolog。这个谓词适用于第一个参数 作为输入,第二个参数作为输出:
?- xml_quote_attribute('<abc>', X).
X = '<abc>'.
但我无法弄清楚如何进行逆向转换。 例如,以下查询无效:
?- xml_quote_attribute(X, '<abc>').
ERROR: Arguments are not sufficiently instantiated
还有另一个谓词可以完成这项工作吗?
再见
答案 0 :(得分:4)
这就是Ruud的解决方案与DCG表示法+推回列表/半文本表示法的对比。
:- use_module(library(dcg/basics)).
html_unescape --> sgml_entity, !, html_unescape.
html_unescape, [C] --> [C], !, html_unescape.
html_unescape --> [].
sgml_entity, [C] --> "&#", integer(C), ";".
sgml_entity, "<" --> "<".
sgml_entity, ">" --> ">".
sgml_entity, "&" --> "&".
使用DCG使代码更具可读性。它还消除了Cookie Monster所指出的一些多余的回溯,这是使用append/3
的结果。
答案 1 :(得分:2)
这是使用字符代码列表的天真解决方案。很可能它不会给你最好的表现,但对于不是很长的琴弦,它可能就好了。
html_unescape("", "") :- !.
html_unescape(Escaped, Unescaped) :-
append("&", _, Escaped),
!,
append(E1, E2, Escaped),
sgml_entity(E1, U1),
!,
html_unescape(E2, U2),
append(U1, U2, Unescaped).
html_unescape(Escaped, Unescaped) :-
append([C], E2, Escaped),
html_unescape(E2, U2),
append([C], U2, Unescaped).
sgml_entity(Escaped, [C]) :-
append(["&#", L, ";"], Escaped),
catch(number_codes(C, L), error(syntax_error(_), _), fail),
!.
sgml_entity("<", "<").
sgml_entity(">", ">").
sgml_entity("&", "&").
您必须自己完成SGML实体列表。
示例输出:
?- html_unescape("<a> 曹操", L), format('~s', [L]).
<a> 曹操
L = [60, 97, 62, 32, 26361, 25805].
答案 2 :(得分:2)
如果您不介意linking a foreign module,那么您可以在C中实现非常高效的实施。
html_unescape.pl:
:- module(html_unescape, [ html_unescape/2 ]).
:- use_foreign_library(foreign('./html_unescape.so')).
html_unescape.c:
#include <stdio.h>
#include <string.h>
#include <SWI-Prolog.h>
static int to_utf8(char **unesc, unsigned ccode)
{
int ok = 1;
if (ccode < 0x80)
{
*(*unesc)++ = ccode;
}
else if (ccode < 0x800)
{
*(*unesc)++ = 192 + ccode / 64;
*(*unesc)++ = 128 + ccode % 64;
}
else if (ccode - 0xd800u < 0x800)
{
ok = 0;
}
else if (ccode < 0x10000)
{
*(*unesc)++ = 224 + ccode / 4096;
*(*unesc)++ = 128 + ccode / 64 % 64;
*(*unesc)++ = 128 + ccode % 64;
}
else if (ccode < 0x110000)
{
*(*unesc)++ = 240 + ccode / 262144;
*(*unesc)++ = 128 + ccode / 4096 % 64;
*(*unesc)++ = 128 + ccode / 64 % 64;
*(*unesc)++ = 128 + ccode % 64;
}
else
{
ok = 0;
}
return ok;
}
static int numeric_entity(char **esc, char **unesc)
{
int consumed;
unsigned ccode;
int ok = (sscanf(*esc, "&#%u;%n", &ccode, &consumed) > 0 ||
sscanf(*esc, "&#x%x;%n", &ccode, &consumed) > 0) &&
consumed > 0 &&
to_utf8(unesc, ccode);
if (ok)
{
*esc += consumed;
}
return ok;
}
static int symbolic_entity(char **esc, char **unesc, char *name, int ccode)
{
int ok = strncmp(*esc, name, strlen(name)) == 0 &&
to_utf8(unesc, ccode);
if (ok)
{
*esc += strlen(name);
}
return ok;
}
static foreign_t pl_html_unescape(term_t escaped, term_t unescaped)
{
char *esc;
if (!PL_get_chars(escaped, &esc, CVT_ATOM | REP_UTF8))
{
PL_fail;
}
else if (strchr(esc, '&') == NULL)
{
return PL_unify(escaped, unescaped);
}
else
{
char buffer[strlen(esc) + 1];
char *unesc = buffer;
while (*esc != '\0')
{
if (*esc != '&' || !(numeric_entity(&esc, &unesc) ||
symbolic_entity(&esc, &unesc, "<", '<') ||
symbolic_entity(&esc, &unesc, ">", '>') ||
symbolic_entity(&esc, &unesc, "&", '&')))
// TODO: more entities...
{
*unesc++ = *esc++;
}
}
return PL_unify_chars(unescaped, PL_ATOM | REP_UTF8, unesc - buffer, buffer);
}
}
install_t install_html_unescape()
{
PL_register_foreign("html_unescape", 2, pl_html_unescape, 0);
}
以下语句将从html_unescape.c构建一个共享库html_unescape.so。在Ubuntu 14.04上测试;可能在Windows上有所不同。
swipl-ld -shared -o html_unescape html_unescape.c
启动SWI-Prolog:
swipl html_unescape.pl
示例输出:
?- html_unescape('<a> 曹操', S).
S = '<a> 曹操'.
特别感谢SWI-Prolog文档和源代码,以及C library to convert unicode code points to UTF8?
答案 3 :(得分:1)
没有渴望成为最终的答案,因为它没有给出 SWI-Prolog的解决方案。对于基于Java的解释器的问题 是XML转义不是J2SE的一部分,至少不是简单的 表格(没有弄清楚如何使用Xerxes等)。
可能的路由是从StringEscapeUtils(*)接口 Apache Commons。但话说回来没有必要 Android因为有一个类TextUtil。所以我们推出了自己的(* *) 很少转换。它的工作原理如下:
?- text_escape('<abc>', X).
X = '<abc>'
?- text_escape(X, '<abc>').
X = '<abc>'
注意使用Java方法codePointAt()和charCount() 在Java源代码中分别附加appendCodePoint()。所以 也可以逃避和超越基本的代码点 平面,即在> 0xFFFF范围内(目前尚未实现, 离开作为练习)。
另一方面,Apache库,至少是2.6版本 不知道代理对,并且每个将放置两个十进制实体 代码点而不是一个。
再见
(*) Java:Class StringEscapeUtils Source
http://grepcode.com/file/repo1.maven.org/maven2/commons-lang/commons-lang/2.6/org/apache/commons/lang/Entities.java#Entities.escape%28java.io.Writer,java.lang.String%29
(* *) Jekejeke Prolog:模块xml
http://www.jekejeke.ch/idatab/doclet/prod/en/docs/05_run/10_docu/05_frequent/07_theories/20_system/03_xml.html