preg_match und UTF-8 in PHP

Lesezeit: 6 Minuten

preg match und UTF 8 in PHP
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?

  • siehe stackoverflow.com/questions/2187615/…

    – Artefakt

    15. August 2010 um 13:53 Uhr

1646645648 339 preg match und UTF 8 in PHP
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]));

  • “Der Modifikator u dient nur dazu, das Muster als UTF-8 zu interpretieren, nicht das Subjekt.” Das ist nicht wahr. Vergleichen Sie zB preg_split('//', .) mit preg_split('//u', .). Da dieses “x wird als UTF-8 interpretiert” etwas vage ist, siehe Das für die tatsächlichen Auswirkungen des Unicode-Modus.

    – Artefakt

    30. August 2010 um 3:41 Uhr

  • Entsprechend nl1.php.net/manual/de/… der u Modifikator wirkt sich sowohl auf das Muster aus und die Eingabe.

    – Lode

    19. Oktober 2012 um 5:36 Uhr


  • @LukaRamishvili Einige Leute sind der Meinung, dass es an vielen Dingen scheiße ist.

    – Michael Robinson

    13. Mai 2014 um 23:29 Uhr


  • @tomalak und die nächsten. Natürlich verwaltet php kein Unicode, da es auf Bytes arbeitet, wenn Sie alte Funktionen wie substr, strlen usw. verwenden, aber es wird seit sehr langer Zeit vollständig über die Erweiterung mbstring verwaltet, die in vielen Distributionen standardmäßig aktiviert ist und Server. Dies ist eine Option, um die Abwärtskompatibilität aufrechtzuerhalten.

    – Daniel-KM

    22. Juni 2017 um 10:19 Uhr


  • @Tomalak “Mann, es ist 2019 und PHP ist bei Unicode immer noch miserabel.” Bitte bestätigen.

    – Pathos

    31. Dezember 2018 um 19:10 Uhr

preg match und UTF 8 in PHP
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

  • Interessant, obwohl ich denke, Sie brauchen die Initiale / Vor dem (*UTF8). Dies funktioniert nicht auf meinem System, aber es könnte auf anderen sein. Was bedeutet diese Ausgabe, wenn Sie dies tun echo $a_matches[0][1];?

    – JW.

    28. Februar 2012 um 0:05 Uhr

  • Ich habe es so auf PHP 5.4.29 verwendet, funktioniert wie ein Zauber: preg_match_all('/(*UTF8)[^A-Za-z0-9\s]/', $txt, $matches);

    – Novalis

    5. Juli 2014 um 8:57 Uhr


  • Funktioniert bei mir weder mit PHP 5.6 noch mit PHP 7 unter Ubuntu 16.04. (*UTF8) vor dem Trennzeichen ist ein Fehler, danach hat es keine Auswirkung. Ich vermute, dass es davon abhängt, wie/wo Sie Ihre PHP bekommen haben, insbesondere die Einstellungen, die libpcre* wurde mit zusammengestellt.

    Benutzer2609094

    24. November 2016 um 16:37 Uhr


  • Ändert die Offsets für mich nicht, aber das ist eine interessante Sache zu wissen. Die Originaldokumentation für dieses “Feature” lautet: pcre.org/pcre.txt

    – BurninLeo

    15. Oktober 2017 um 15:29 Uhr

1646645649 715 preg match und UTF 8 in PHP
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”).

  • Großartig … und sie bieten kein mb_preg_replace.

    – JW.

    12. November 2009 um 22:21 Uhr

  • Beachten Sie, dass für den 5. Parameter die gleichen “Regeln” bezüglich der Handhabung von utf-8 gelten $offset. Probe: var_dump(preg_match('/#/u', "\xc3\xa4#",$matches,0,2));

    – Athanasius Kirchner

    24. Februar 2016 um 9:36 Uhr


  • php kennt den Modifikator u, der im Handbuch aufgeführt ist, siehe “u (PCRE_UTF8)” php.net/manual/en/reference.pcre.pattern.modifiers.php

    – Walt Sörensen

    7. Mai 2017 um 14:40 Uhr

1646645650 503 preg match und UTF 8 in PHP
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

  • Das war nur ein vereinfachtes Beispiel, aber das kann für andere nützlich sein.

    – JW.

    16. August 2011 um 22:45 Uhr

1646645651 608 preg match und UTF 8 in PHP
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

  • Das war nur ein vereinfachtes Beispiel, aber das kann für andere nützlich sein.

    – JW.

    16. August 2011 um 22:45 Uhr

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.

964830cookie-checkpreg_match und UTF-8 in PHP

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy