You may match the specific parts of the input string using a single pattern with capturing groups:
preg_match('~^(?<code>\S+)\s+(?<name>.*?)\s+(?<num>\$\d[\d.]*)\s*(?<details>.*)$~', $text, $matches)
See the regex demo. Actually, the last $ is not required, it is there just to show the whole string is matched.
Details
^ - start of a string
(?<code>\S+) - Group "code": one or more non-whitespace chars
\s+ - 1+ whitespaces
(?<name>.*?) - Group "name": any 0+ chars other than line break chars, as few as possible
\s+ - 1+ whitespaces
(?<num>\$\d[\d.]*) - Group "num": a $, then 1 digit and then 0+ digits or .
\s* - 0+ whitespaces
(?<details>.*) - Group "details": any 0+ chars other than line break chars, as many as possible
$ - end of string.
PHP code:
$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"];
}
Output:
Code: BK0001
Name: My book (4th Edition)
Price: $49.95
Details: (Clearance Price!)
preg_match('~^(?<code>\S+)\s+(?<name>.*?)\s+(\$\d[\d.]*)\s*(?<details>.*)$~', $text, $matches), see demo.learning it fully really a good option right nowit's always good to learn Regex, most languages have some flavor of it and it's incredibly powerful and useful.