4
votes

I've been wrapping my head around this for days now, but nothing seems to give the desired result.

Example:

$var = "Some Words - Other Words (More Words) Dash-Binded-Word";

Desired result:

array(
[0] => Some Words
[1] => Other Words
[2] => More Words
[3] => Dash-Bound-Word
)

I was able to get this all working using preg_match_all, but then the "Dash-Bound-Word" was broken up as well. Trying to match it with surrounding spaces didn't work as it would break all the words except the dash bound ones.

The preg_match_all statement I used (which broke up the dash bound words too) is this:

preg_match_all('#\(.*?\)|\[.*?\]|[^?!\-|\(|\[]+#', $var, $array);

I'm certainly no expert on preg_match, preg_split so any help here would be greatly appreciated.

5
Nevermind. Explode may not work the way you want it in this case. - Maximus2012
@Maximus2012 I tried explode() before starting with preg_match_all, and although I was able to explode the dashes, I didn't get it to work for parts that are between the brackets. :( Thank you for the tip though. If you know a way to get it working via that way that would be awesome. - Sascha
See my answer below and see if it helps. It will work for this case but you might have to make changes if you plan to use it for other cases too. - Maximus2012

5 Answers

5
votes

You can use a simple preg_match_all:

\w+(?:[- ]\w+)*

See demo

  • \w+ - 1 or more alphanumeric or underscore
  • (?:[- ]\w+)* - 0 or more sequences of...
    • [- ] - a hyphen or space (you may change space to \s to match any whitespace)
    • \w+ - 1 or more alphanumeric or underscore

IDEONE demo:

$re = '/\w+(?:[- ]\w+)*/'; 
$str = "Some Words - Other Words (More Words) Dash-Binded-Word"; 
preg_match_all($re, $str, $matches);
print_r($matches[0]);

Result:

Array
(
    [0] => Some Words
    [1] => Other Words
    [2] => More Words
    [3] => Dash-Binded-Word
)
2
votes

You can split by:

/\s*(?<!\w(?=.\w))[\-[\]()]\s*/

Explanation:

  1. The match is attempted against the character class [\-[\]()] (matches any of those characters). You could also add any char you want to that character class.
  2. It's using a negative lookbehind (?<!\w) for the condition: "not preceded by a word character".
  3. And it also has a nested lookahead (?=.\w) that checks for: "if the first condition is met, it shouldn't be followed by any char -the one used to split- and a word character".
  4. \s* at the beggining and the end is to trim whitespaces.

Code:

$input_line = "Some Words - Other Words (More Words) Dash-Binded-Word";
$result = preg_split("/\s*(?<!\w(?=.\w))[\-[\]()]\s*/", $input_line);
var_dump($result);

Output:

array(4) {
  [0]=>
  string(10) "Some Words"
  [1]=>
  string(11) "Other Words"
  [2]=>
  string(10) "More Words"
  [3]=>
  string(16) "Dash-Binded-Word"
}

Run this code here

Capturing parens

As stated in another comment, if you want to also capture parentheses:

$result = preg_split("/\s*(?:(?<!\w)-(?!\w)|(\(.*?\)|\[.*?]))\s*/", $input_line, -1, PREG_SPLIT_DELIM_CAPTURE);
0
votes

Modifying the input string to suit any particular exploding technique would be indirect and indicate that a suboptimal exploding technique is being used.

The truth is, your required logic can be boiled down to: "explode on each sequence of non-word characters that have a length of 2 or more". This is what that pattern looks like with preg_split().

Code: (Demo)

$var = "Some Words - Other Words (More Words) Dash-Binded-Word";

var_export(preg_split('~\W{2,}~', $var));

Output:

array (
  0 => 'Some Words',
  1 => 'Other Words',
  2 => 'More Words',
  3 => 'Dash-Binded-Word',
)

It doesn't get any simpler than that.

-1
votes

Try this (combination of str_replace and explode). It is not optimum but may work for this case:

$var = "Some Words - Other Words (More Words) Dash-Binded-Word";
$arr = Array(" - ", " (", ") ");
$var2 = str_replace($arr, "|", $var);
$final = explode('|', $var2);
var_dump($final);

Output:

array(4) { [0]=> string(10) "Some Words" [1]=> string(11) "Other Words" [2]=> string(10) "More Words" [3]=> string(16) "Dash-Binded-Word" }

-1
votes
$var = "Some Words - Other Words (More Words) Dash-Binded-Word";

$var=preg_replace('/[^A-Za-z\-]/', ' ', $var);
$var=str_replace('-', ' ', $var); // Replaces all hyphens with spaces.
print_r (explode(" ",preg_replace('!\s+!', ' ', $var)));  //replaces all multiple spaces with one and explode creates array split where there is space

OUTPUT :-

Array ( [0] => Some [1] => Words [2] => Other [3] => Words [4] => More [5] => Words [6] => Dash [7] => Binded [8] => Word )