Regex - Как я могу получить этот шаблон <img src="/storage/5/articles/pictures/15_sdf8g.jpeg"> правильно? - PullRequest
2 голосов
/ 14 июня 2019

У меня есть тело из сообщения, где пользователь может или не может вставить изображение.Мне нужно получить каждое вхождение этого изображения в посте.Вот пример:

<img src="/storage/USER_ID/articles/pictures/FILENAME">

Итак, допустим, у меня будет это тело:

$body = "... Cras ut tristique est. Etiam porttitor elit velit, vitae consequat eros interdum ac. Nam in blandit ante.</p><p>&nbsp;</p><figure class="image"><img src="/storage/5/articles/pictures/1560534410321_a363bc0d804aec432567128ed10416ee.jpeg"></figure><p>Integer sed justo accumsan, consequat nulla at, tincidunt massa. Integer orna Etiam porttitor elit velit, vitae consequat eros interdum ac. Nam in blandit ante.</p><p>&nbsp;</p><figure class="image"><img src="/storage/5/articles/pictures/23456410321_a33456t604aec432567128ed10416ee.jpeg"></figure> j hgfjhf  jfhfj hgf jh786 876 8 76fgj tfyt u  ufgi uyu y gi iy gygg ...";

Я хочу получить число 5 и имя файла 1560534410321_a363bc0d804aec432567128ed10416ee.jpeg

и число 5 и имя файла 23456410321_a33456t604aec432567128ed10416ee.jpeg

Так что в этом сценарии я думаю, что шаблон должен быть таким: получить любое число и имя файла между <img src="/storage/ число /articles/pictures/ имя файла ">

Это то, что я до сих пор:

preg_match_all ('/<img src=\"\/storage\/(.*?)\/articles\/pictures\/(.*?)\.(.*?)\"\>/g', $body , $result);

Как я могуулучшите этот REGEX, чтобы иметь сценарий, где " заменяется на '?

Ответы [ 5 ]

2 голосов
/ 15 июня 2019

Избегайте анализа HTML с помощью регулярных выражений.

Лучше сначала сузить значения, которые вам нужны, а затем сделать регулярное выражение, если вам нужно.

<?php
$body = '...';

$dom_err = libxml_use_internal_errors(true);
$dom = new DOMDocument();
$dom->loadHtml($body, LIBXML_HTML_NOIMPLIED | LIBXML_HTML_NODEFDTD);

$xpath = new DOMXPath($dom);

$imgs = [];
foreach ($xpath->query("//figure/img") as $img) {
    $src = $img->getAttribute('src');

    if (preg_match('#/storage/(.*)/articles/pictures/(.*)#', $src, $result)) {
        $imgs[] = [
            'id' => $result[1],
            'name' => $result[2]
        ];
    }
}

libxml_clear_errors();
libxml_use_internal_errors($dom_err);

print_r($imgs);

Результат:

Array
(
    [0] => Array
        (
            [id] => 5
            [name] => 1560534410321_a363bc0d804aec432567128ed10416ee.jpeg
        )

    [1] => Array
        (
            [id] => 5
            [name] => 23456410321_a33456t604aec432567128ed10416ee.jpeg
        )

)

Демо

0 голосов
/ 15 июня 2019

Вот два пункта:

Если вы пытаетесь извлечь информацию из HTML / XML, используйте соответствующий парсер. В большинстве случаев это означает DOM. Вы можете использовать выражения Xpath для извлечения узлов. Это ограничивается тем, что PHP поддерживает только Xpath 1.0, а это означает только простые строковые функции. Однако вы можете нарушить это, ограничивая регистрацию и вызов функций PHP из Xpath.

$html = <<<'HTML'
<img src="/storage/USER_ID/articles/pictures/FILENAME">
HTML;

$document = new DOMDocument();
$document->loadHTML($html);
$xpath = new DOMXpath($document);

$expression = '//img[starts-with(@src, "/storage/")]';

foreach ($xpath->evaluate($expression) as $imageNode) {
    var_dump($imageNode->getAttribute('src'));
}

Выход:

string(43) "/storage/USER_ID/articles/pictures/FILENAME"

Это лучший способ. Парсер позаботится о специфике формата, такой как кавычки или декодирующие объекты.

Однако, если вам действительно нравится / нужно использовать RegEx - шаблон PCRE, соответствующий альтернативным символам, легко, просто используйте класс символов, такой как (?<quote>["']), или альтернативный шаблон, такой как (?<quote>"|'), заключенный в именованный шаблон. С этим вы можете ссылаться на него для заключительной цитаты. Вот сжатый пример:

$pattern = '((?<quote>[\'"])(?<content>.*)?\g{quote})';
$subject = <<<'DATA'
'foo' "bar"
DATA;

preg_match_all($pattern, $subject, $matches);
var_dump($matches['content']);

Выход:

array(2) { 
  [0]=> 
  string(3) "foo" 
  [1]=> 
  string(3) "bar" 
}
0 голосов
/ 15 июня 2019

Это работает

<img(?=\s)(?=(?:[^>"']|"[^"]*"|'[^']*')*?\ssrc\s*=\s*(?:(['"])(?:(?!\1)[\S\s])*?/storage/(\d+)/articles/pictures/((?:(?!\1)[\S\s])*)\1))\s+(?:"[\S\s]*?"|'[\S\s]*?'|[^>]*?)+>

Номер в группе 2, имя файла в группе 3.

https://regex101.com/r/4oSMXl/1

Объяснено

 # Begin open img tag

 < img
 (?= \s )
 (?=                    # Asserttion (a pseudo atomic group)
      (?: [^>"'] | " [^"]* " | ' [^']* ' )*?
      \s src \s* = \s*       # Src Attribute
      (?:
           ( ['"] )               # (1), Quote
           (?:                    # Src Value
                (?! \1 )
                [\S\s] 
           )*?

           /storage/
           ( \d+ )                # (2), Number
           /articles/pictures/

           (                      # (3 start), Filename, general to end of string
                (?:
                     (?! \1 )
                     [\S\s] 
                )*
           )                      # (3 end)
           \1                     # End Quote
      )
 )
                        # Have the code, just match the rest of tag
 \s+ 
 (?: " [\S\s]*? " | ' [\S\s]*? ' | [^>]*? )+

 >                      # End img tag
0 голосов
/ 15 июня 2019

Здесь мы будем использовать простое выражение с preg_match_all:

src=".*?([^\/]+\.[a-z]+)?"

и желаемый результат находится в этой группе захвата:

([^\/]+\.[a-z]+)

Демо

Тест

$re = '/src=".*?([^\/]+\.[a-z]+)?"/m';
$str = '... Cras ut tristique est. Etiam porttitor elit velit, vitae consequat eros interdum ac. Nam in blandit ante.</p><p>&nbsp;</p><figure class="image"><img src="/storage/5/articles/pictures/1560534410321_a363bc0d804aec432567128ed10416ee.jpeg"></figure><p>Integer sed justo accumsan, consequat nulla at, tincidunt massa. Integer orna Etiam porttitor elit velit, vitae consequat eros interdum ac. Nam in blandit ante.</p><p>&nbsp;</p><figure class="image"><img src="/storage/5/articles/pictures/23456410321_a33456t604aec432567128ed10416ee.jpeg"></figure> j hgfjhf  jfhfj hgf jh786 876 8 76fgj tfyt u  ufgi uyu y gi iy gygg ...';

preg_match_all($re, $str, $matches, PREG_SET_ORDER, 0);

foreach ($matches as $key => $value) {
    echo $value[1] . "\n";
}

выход

1560534410321_a363bc0d804aec432567128ed10416ee.jpeg
23456410321_a33456t604aec432567128ed10416ee.jpeg
0 голосов
/ 15 июня 2019

Вы должны использовать синтаксический анализ HTML DOM, а затем REGEX .

DomDocument является хорошим примером встроенной библиотеки, которую легко настроить.

Вы можете использовать это, чтобы получить строковое значение свойства src изображения:

<?php

// Create a DOM object from a string
$dom = new DOMDocument;
$dom->loadHTML($string);

// Find all <img> with the id=foo attribute
$images = $dom->getElementsByTagName('img');

//Loop through all the images and print their 'src' tag
foreach ($images as $image) {
    echo $image->getAttribute('src');
}

?>

Хотя эта библиотека довольно ограничена, она сохранит небольшую и относительно эффективную базу кода без необходимости что-либо загружать. :)

После анализа html вы можете использовать регулярное выражение в качестве одного из многих способов получить нужную информацию из пути к файлу.

Следующее выражение регулярного выражения будет работать для упрощения строки в различных частях USER_ID и FILENAME.

DEMO

<?php

$string = "/storage/5/articles/pictures/1560534410321_a363bc0d804aec432567128ed10416ee.jpeg";

// Perform Regex
$array = preg_match('\/storage\/(\d+)\/articles\/pictures\/((?:[\S\s])*)', $string);

$user_id = $array[1];
$filename = $array[2];

?>
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...