Разделить строку на несколько частей с помощью регулярного выражения

У меня есть строка, как

BK0001 My book (4th Edition) $49.95 (Clearance Price!)

Я хотел бы разделить его на разные части, например

[BK0001] 
[My Book (4th Edition)] 
[$49.95] 
[(Clearance Price!)]

Я новичок в регулярных выражениях, и я использую это для анализа строки в файле. Мне удалось получить первую часть BK0001 с помощью

$parts = preg_split('/\s+/', 'BK0001 My book (4th Edition) $49.95 (Clearance Price!)';

затем получите значение $part[0], но не знаете, как разделить его, чтобы получить другие значения.


person answerSeeker    schedule 07.11.2018    source источник
comment
вы уже использовали regex101? Отличный ресурс как для изучения регулярных выражений, так и для разработки под конкретные нужды.   -  person Daniel Farrell    schedule 07.11.2018
comment
Попробуйте расшифровать подшаблоны. Скажем, preg_match('~^(?<code>\S+)\s+(?<name>.*?)\s+(\$\d[\d.]*)\s*(?<details>.*)$~', $text, $matches), см. демонстрацию.   -  person Wiktor Stribiżew    schedule 07.11.2018
comment
@Dan Farrel У меня есть, но я не часто использую php и регулярные выражения, я пишу код в основном на python и обычно использую string.split() для таких задач, как эти. Это один из тех редких моментов, когда мне нужно регулярное выражение, и потратить время на его полное изучение действительно хороший вариант прямо сейчас.   -  person answerSeeker    schedule 07.11.2018
comment
@WiktorStribiżew отлично работает. Спасибо   -  person answerSeeker    schedule 07.11.2018
comment
learning it fully really a good option right now Всегда хорошо изучать Regex, в большинстве языков есть что-то от него, и он невероятно мощный и полезный.   -  person ArtisticPhoenix    schedule 08.11.2018


Ответы (2)


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

preg_match('~^(?<code>\S+)\s+(?<name>.*?)\s+(?<num>\$\d[\d.]*)\s*(?<details>.*)$~', $text, $matches)

См. демонстрацию регулярного выражения. На самом деле последний $ не требуется, он нужен только для того, чтобы показать соответствие всей строки.

Подробнее

  • ^ - начало строки
  • (?<code>\S+) - Групповой "код": один или несколько непробельных символов
  • \s+ - 1+ пробелов
  • (?<name>.*?) — Групповое «имя»: любые 0+ символов, кроме символов разрыва строки, как можно меньше
  • \s+ - 1+ пробелов
  • (?<num>\$\d[\d.]*) - Группа "число": $, затем 1 цифра, а затем 0+ цифр или .
  • \s* - 0+ пробелов
  • (?<details>.*) — Групповые «детали»: любые 0+ символов, кроме символов разрыва строки, как можно больше
  • $ - конец строки.

код PHP:

$re = '~^(?<code>\S+)\s+(?<name>.*?)\s+(?<num>\$\d[\d.]*)\s*(?<details>.*)$~';
$str = 'BK0001 My book (4th Edition) $49.95 (Clearance Price!)';
if (preg_match($re, $str, $m)) {
    echo "Code: " . $m["code"] . "\nName: " . $m["name"] . "\nPrice: " .
         $m["num"] . "\nDetails: " . $m["details"]; 
}

Выход:

Code: BK0001
Name: My book (4th Edition)
Price: $49.95
Details: (Clearance Price!)
person Wiktor Stribiżew    schedule 07.11.2018
comment
@answerSeeker, в этом сила ссылки regex101. Вы всегда можете включить то же самое в свой вопрос. - person Daniel Farrell; 08.11.2018

Попробуйте использовать preg_match

$book_text = "BK0001 My book (4th Edition) $49.95 (Clearance Price!)";
if(preg_match("/([\w\d]+)\s+(.*?)\s+\\((.*?)\\)\s+(\\$[\d\.]+)\s+\\((.*?)\\)$/",$book_text,$matches)) {
    //Write code here
    print_r($matches);
}

$matches[0] зарезервирован для полной строки соответствия. Вы можете найти разделенные части из $matches[1]...

Array ( [0] => BK0001 My book (4th Edition) $49.95 (Clearance Price!) [1] => BK0001 [2] => My book [3] => 4th Edition [4] => $49.95 [5] => Clearance Price! )

$matches[1] is "book number"
$matches[2] is "book name"
$matches[3] is "edition"
$matches[4] is "price"
$matches[5] is "special text"
person Ravi Rajendra    schedule 07.11.2018