
JW.
Ich versuche, eine UTF8-codierte Zeichenfolge mit zu suchen preg_match.
preg_match('/H/u', "\xC2\xA1Hola!", $a_matches, PREG_OFFSET_CAPTURE);
echo $a_matches[0][1];
Dies sollte 1 ausgeben, da “H” an Index 1 in der Zeichenfolge “¡Hola!” steht. Aber es gibt 2 aus. Es scheint also, als würde es das Thema nicht als UTF8-codierte Zeichenfolge behandeln, obwohl ich das “u” übergebe Modifikator im regulären Ausdruck.
Ich habe die folgenden Einstellungen in meiner php.ini und andere UTF8-Funktionen funktionieren:
mbstring.func_overload = 7
mbstring.language = Neutral
mbstring.internal_encoding = UTF-8
mbstring.http_input = pass
mbstring.http_output = pass
mbstring.encoding_translation = Off
Irgendwelche Ideen?

Gumbo
Obwohl die u Modifikator bewirkt, dass sowohl das Muster als auch der Betreff als UTF-8 interpretiert werden, die erfassten Offsets werden weiterhin in Bytes gezählt.
Sie können verwenden mb_strlen
um die Länge in UTF-8-Zeichen statt in Bytes zu erhalten:
$str = "\xC2\xA1Hola!";
preg_match('/H/u', $str, $a_matches, PREG_OFFSET_CAPTURE);
echo mb_strlen(substr($str, 0, $a_matches[0][1]));

Natxet
Versuchen Sie, dies hinzuzufügen (*UTF8) vor der Regex:
preg_match('(*UTF8)/H/u', "\xC2\xA1Hola!", $a_matches, PREG_OFFSET_CAPTURE);
Magic, dank eines Kommentars in
https://www.php.net/manual/function.preg-match.php#95828

Benutzer187291
Sieht so aus, als wäre dies ein “Feature”, siehe
http://bugs.php.net/bug.php?id=37391
Der ‘u’-Schalter macht nur für pcre Sinn, PHP selbst ist sich dessen nicht bewusst.
Aus Sicht von PHP sind Strings Byte-Sequenzen und die Rückgabe eines Byte-Offsets erscheint logisch (ich sage nicht “richtig”).

Guy Fawkes
Entschuldigen Sie das Necroposting, aber vielleicht findet es jemand nützlich: Der folgende Code kann sowohl als Ersatz für die Funktionen preg_match als auch preg_match_all dienen und gibt korrekte Übereinstimmungen mit zurück Korrekt Offset für UTF8-kodierte Strings.
mb_internal_encoding('UTF-8');
/**
* Returns array of matches in same format as preg_match or preg_match_all
* @param bool $matchAll If true, execute preg_match_all, otherwise preg_match
* @param string $pattern The pattern to search for, as a string.
* @param string $subject The input string.
* @param int $offset The place from which to start the search (in bytes).
* @return array
*/
function pregMatchCapture($matchAll, $pattern, $subject, $offset = 0)
{
$matchInfo = array();
$method = 'preg_match';
$flag = PREG_OFFSET_CAPTURE;
if ($matchAll) {
$method .= '_all';
}
$n = $method($pattern, $subject, $matchInfo, $flag, $offset);
$result = array();
if ($n !== 0 && !empty($matchInfo)) {
if (!$matchAll) {
$matchInfo = array($matchInfo);
}
foreach ($matchInfo as $matches) {
$positions = array();
foreach ($matches as $match) {
$matchedText = $match[0];
$matchedLength = $match[1];
$positions[] = array(
$matchedText,
mb_strlen(mb_strcut($subject, 0, $matchedLength))
);
}
$result[] = $positions;
}
if (!$matchAll) {
$result = $result[0];
}
}
return $result;
}
$s1 = 'Попробуем русскую строку для теста';
$s2 = 'Try english string for test';
var_dump(pregMatchCapture(true, '/обу/', $s1));
var_dump(pregMatchCapture(false, '/обу/', $s1));
var_dump(pregMatchCapture(true, '/lish/', $s2));
var_dump(pregMatchCapture(false, '/lish/', $s2));
Ausgabe meines Beispiels:
array(1) {
[0]=>
array(1) {
[0]=>
array(2) {
[0]=>
string(6) "обу"
[1]=>
int(4)
}
}
}
array(1) {
[0]=>
array(2) {
[0]=>
string(6) "обу"
[1]=>
int(4)
}
}
array(1) {
[0]=>
array(1) {
[0]=>
array(2) {
[0]=>
string(4) "lish"
[1]=>
int(7)
}
}
}
array(1) {
[0]=>
array(2) {
[0]=>
string(4) "lish"
[1]=>
int(7)
}
}
Wenn Sie nur die Multibyte-sichere Position von H finden möchten, versuchen Sie es mit mb_strpos()
mb_internal_encoding('UTF-8');
$str = "\xC2\xA1Hola!";
$pos = mb_strpos($str, 'H');
echo $str."\n";
echo $pos."\n";
echo mb_substr($str,$pos,1)."\n";
Ausgabe:
¡Hola!
1
H

bronek89
Ich habe eine kleine Klasse geschrieben, um die von preg_match zurückgegebenen Offsets in die richtigen utf-Offsets zu konvertieren:
final class NonUtfToUtfOffset
{
/** @var int[] */
private $utfMap = [];
public function __construct(string $content)
{
$contentLength = mb_strlen($content);
for ($offset = 0; $offset < $contentLength; $offset ++) {
$char = mb_substr($content, $offset, 1);
$nonUtfLength = strlen($char);
for ($charOffset = 0; $charOffset < $nonUtfLength; $charOffset ++) {
$this->utfMap[] = $offset;
}
}
}
public function convertOffset(int $nonUtfOffset): int
{
return $this->utfMap[$nonUtfOffset];
}
}
Sie können es so verwenden:
$content="aą bać d";
$offsetConverter = new NonUtfToUtfOffset($content);
preg_match_all('#(bać)#ui', $content, $m, PREG_OFFSET_CAPTURE);
foreach ($m[1] as [$word, $offset]) {
echo "bad: " . mb_substr($content, $offset, mb_strlen($word))."\n";
echo "good: " . mb_substr($content, $offsetConverter->convertOffset($offset), mb_strlen($word))."\n";
}
https://3v4l.org/8Y32J
Vielleicht möchten Sie sich ansehen T-Regx Bücherei.
pattern('/Hola/u')->match('\xC2\xA1Hola!')->first(function (Match $match)
{
echo $match->offset(); // characters
echo $match->byteOffset(); // bytes
});
Dies $match->offset()
ist UTF-8 sicherer Offset.
9648300cookie-checkpreg_match und UTF-8 in PHPyes
siehe stackoverflow.com/questions/2187615/…
– Artefakt
15. August 2010 um 13:53 Uhr