我使用DOMDocument在输出到页面之前操作/修改HTML。这只是一个html片段,而不是一个完整的页面。我最初的问题是所有的法国人都搞砸了,经过一番试错后我才能纠正。现在,似乎只有一个问题仍然存在:'角色变成了?
代码:
<?php
$dom = new DOMDocument('1.0','utf-8');
$dom->loadHTML(utf8_decode($row->text));
//Some pretty basic modification here, not even related to text
//reinsert HTML, and make sure to remove DOCTYPE, html and body that get added auto.
$row->text = utf8_encode(preg_replace('/^<!DOCTYPE.+?>/', '', str_replace( array('<html>', '</html>', '<body>', '</body>'), array('', '', '', ''), $dom->saveHTML())));
?>
我知道utf8解码/编码越来越混乱,但这是迄今为止我能使它工作的唯一方法。这是一个示例字符串:
输入: Sans doute parce qu'il vient d'atteind datedéterminantedansson spectaculaire cheminement
输出: Sans doute parce qu?il vient d?atteind date d'déminanantedans son spectaculaire cheminement
如果我发现更多细节,我会添加它们。感谢您的时间和支持!
答案 0 :(得分:16)
请勿使用utf8_decode
。如果您的文本是UTF-8,请将其传递给它。
不幸的是,如果是HTML,DOMDocument
默认为LATIN1。似乎行为就是这个
工作示例:
<?php
$s = <<<HTML
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
</head>
<body>
Sans doute parce qu’il vient d’atteindre une date déterminante
dans son spectaculaire cheminement
</body>
</html>
HTML;
libxml_use_internal_errors(true);
$d = new domdocument;
$d->loadHTML($s);
echo $d->textContent;
使用XML(默认为UTF-8):
<?php
$s = '<x>Sans doute parce qu’il vient d’atteindre une date déterminante'.
'dans son spectaculaire cheminement</x>';
libxml_use_internal_errors(true);
$d = new domdocument;
$d->loadXML($s);
echo $d->textContent;
答案 1 :(得分:7)
loadHtml()
并不总能识别Content-type HTTP-EQUIV元标记中指定的正确编码。
如果DomDocument('1.0', 'UTF-8')
和loadHTML('<?xml version="1.0" encoding="UTF-8"?>' . $html)
黑客无法正常工作(PHP 5.3.13),请尝试以下操作:
在打开<head>
标记后立即添加另一个<html>
部分,其中包含正确的内容类型HTTP-EQUIV元标记。然后拨打loadHtml()
,然后删除额外的<head>
代码。
// Ensure entire page is encoded in UTF-8
$encoding = mb_detect_encoding($body);
$body = $encoding ? @iconv($encoding, 'UTF-8', $body) : $body;
// Insert a head and meta tag immediately after the opening <html> to force UTF-8 encoding
$insertPoint = false;
if (preg_match("/<html.*?>/is", $body, $matches, PREG_OFFSET_CAPTURE)) {
$insertPoint = mb_strlen( $matches[0][0] ) + $matches[0][1];
}
if ($insertPoint) {
$body = mb_substr(
$body,
0,
$insertPoint
) . "<head><meta http-equiv='Content-type' content='text/html; charset=UTF-8' /></head>" . mb_substr(
$body,
$insertPoint
);
}
$dom = new DOMDocument();
// Suppress warnings for loading non-standard html pages
libxml_use_internal_errors(true);
$dom->loadHTML($body);
libxml_use_internal_errors(false);
// Now remove extra <head>
请参阅此文章:http://devzone.zend.com/1538/php-dom-xml-extension-encoding-processing/
答案 2 :(得分:4)
这对我来说已经足够了,这里的其他答案都是矫枉过正的。鉴于我有一个带有现有HEAD标签的HTML文档。 HEAD标签没有属性,我没有问题在我的用例的HTML中留下额外的META标签。
$data = str_ireplace('<head>', '<head><meta http-equiv="Content-Type" content="text/html; charset=utf-8" />', $data);
$document = new DOMDocument();
$document->loadHTML($data);
答案 3 :(得分:1)
正如其他人指出的那样,DOMDocument
和LoadHTML
将默认为带有HTML片段的LATIN1编码。它还将使用以下内容包装HTML:
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd">
<html><body>YOUR HTML</body></html>
正如其他人所指出的那样,您可以通过将HEAD元素插入包含具有正确编码的META元素的HTML中来修复编码。
但是,如果您使用的是HTML片段,则可能不希望自动换行,也不想保留插入的HEAD元素。
以下代码将插入HEAD元素,然后在处理后使用正则表达式将删除所有包装元素:
<?php
$html = '<article class="grid-item"><p>Hello World</p></article><article class="grid-item"><p>Goodbye World</p></article>';
$head = '<head><meta http-equiv="Content-Type" content="text/html; charset=utf-8" /></head>';
libxml_use_internal_errors(true);
$dom = new DOMDocument('1.0', 'utf-8');
$dom->loadHTML($head . $html);
$xpath = new DOMXPath($dom);
// Loop through all article.grid-item elements and add the "invisible" class to them
$nodes = $xpath->query("//article[contains(concat(' ', normalize-space(@class), ' '), ' grid-item ')]");
foreach($nodes as $node) {
$class = $node->getAttribute('class');
$class .= ' invisible';
$node->setAttribute('class', $class);
}
$content = preg_replace('/<\/?(!doctype|html|head|meta|body)[^>]*>/im', '', $dom->saveHTML());
libxml_use_internal_errors(false);
echo $content;
?>