12

I'm trying to split strings in half, and it should not split in the middle of a word.

So far I came up with the following which is 99% working :

$text = "The Quick : Brown Fox Jumped Over The Lazy / Dog";
$half = (int)ceil(count($words = str_word_count($text, 1)) / 2); 
$string1 = implode(' ', array_slice($words, 0, $half));
$string2 = implode(' ', array_slice($words, $half));

This does work, correctly splitting any string in half according to the number of words in the string. However, it is removing any symbols in the string, for example for the above example it would output :

The Quick Brown Fox Jumped
Over The Lazy Dog

I need to keep all the symbols like : and / in the string after being split. I don't understand why the current code is removing the symbols... If you can provide an alternative method or fix this method to not remove symbols, it would be greatly appreciated :)

Leo44
  • 160
  • 1
  • 1
  • 10
  • I find the required logic to be ambiguous. Are you trying to balance the number of words in each half, or are you trying to get a balanced number of characters in each half without breaking the middle word? A [mcve] with a battery of sample strings which express different fringe cases would have helped this question. – mickmackusa Apr 27 '21 at 09:44

8 Answers8

24

Upon looking at your example output, I noticed all our examples are off, we're giving less to string1 if the middle of the string is inside a word rather then giving more.

For example the middle of The Quick : Brown Fox Jumped Over The Lazy / Dog is The Quick : Brown Fox Ju which is in the middle of a word, this first example gives string2 the split word; the bottom example gives string1 the split word.

Give less to string1 on split word

$text = "The Quick : Brown Fox Jumped Over The Lazy / Dog";

$middle = strrpos(substr($text, 0, floor(strlen($text) / 2)), ' ') + 1;

$string1 = substr($text, 0, $middle);  // "The Quick : Brown Fox "
$string2 = substr($text, $middle);  // "Jumped Over The Lazy / Dog"

Give more to string1 on split word

$text = "The Quick : Brown Fox Jumped Over The Lazy / Dog";

$splitstring1 = substr($text, 0, floor(strlen($text) / 2));
$splitstring2 = substr($text, floor(strlen($text) / 2));

if (substr($splitstring1, 0, -1) != ' ' AND substr($splitstring2, 0, 1) != ' ')
{
    $middle = strlen($splitstring1) + strpos($splitstring2, ' ') + 1;
}
else
{
    $middle = strrpos(substr($text, 0, floor(strlen($text) / 2)), ' ') + 1;    
}

$string1 = substr($text, 0, $middle);  // "The Quick : Brown Fox Jumped "
$string2 = substr($text, $middle);  // "Over The Lazy / Dog"
Jeff Wilbert
  • 4,400
  • 1
  • 20
  • 35
  • Thanks, it could definitely be useful to choose whether the first or second string gets the split word. In my current project I would like to give more to string1, and using my original 'quick brown fox' example your code does work as intended, however testing with other strings seems to have mixed results, for example `$text = "one two three four five one two three four five";` results in string1 being only `one two three four`. In any case I am awarding you the answer because your first code does the job exactly as I asked. – Leo44 Nov 19 '11 at 09:11
  • Actually after further testing I believe the 2nd code does work as intended, unless the exact half point of the string is a space. That probably won't happen often so it will work fine :) – Leo44 Nov 19 '11 at 09:17
  • 1
    Alternative suggestion to give more to string1: $middle = strpos($name, ' ', floor(strlen($name)*0.5)); – cmc Dec 17 '14 at 16:42
  • @jeff-wilbert any chance you can help expand on this? my question posted at: http://stackoverflow.com/questions/42505200/split-input-string-in-php-into-multiple-parts-without-breaking-words – MitchellK Feb 28 '17 at 10:09
8
function split_half($string, $center = 0.4) {
        $length2 = strlen($string) * $center;
        $tmp = explode(' ', $string);
        $index = 0; 
        $result = Array('', '');
        foreach($tmp as $word) {
            if(!$index && strlen($result[0]) > $length2) $index++;
            $result[$index] .= $word.' ';
        }
        return $result;
}

Demo: http://codepad.viper-7.com/I58gcI

Peter
  • 16,453
  • 8
  • 51
  • 77
  • Thanks for providing a function with demo, it does seem to work as intended. – Leo44 Nov 19 '11 at 09:03
  • 2
    None of the others worked for me except this one. I made a slight change that fixes the problem of only 2 words, and the second being longer by adding ```if(count($tmp) < 3) { return $tmp; }``` after the ```explode``` – B-Stewart Aug 31 '17 at 23:09
  • This answer is missing its educational explanation. – mickmackusa Apr 27 '21 at 10:25
4

I know this is an old question, but I have the following piece of code that should do what is needed.

It by default it splits the string on the first occurrence of a space after the middle. If there are no spaces after the middle, it looks for the last space before the middle.

function trim_text($input) {
    $middle = ceil(strlen($input) / 2);
    $middle_space = strpos($input, " ", $middle - 1);

    if ($middle_space === false) {
        //there is no space later in the string, so get the last sapce before the middle
        $first_half = substr($input, 0, $middle);
        $middle_space = strpos($first_half, " ");
    }

    if ($middle_space === false) {
        //the whole string is one long word, split the text exactly in the middle
        $first_half = substr($input, 0, $middle);
        $second_half = substr($input, $middle);
    }
    else {
        $first_half = substr($input, 0, $middle_space);
        $second_half = substr($input, $middle_space);
    }
        return array(trim($first_half), trim($second_half));
}

These are examples:

Example 1:

"WWWWWWWWWW WWWWWWWWWW WWWWWWWWWW WWWWWWWWWW"

Is split as

"WWWWWWWWWW WWWWWWWWWW"

"WWWWWWWWWW WWWWWWWWWW"

Example 2:

"WWWWWWWWWWWWWWWWWWWW WWWWWWWWWW WWWWWWWWWW"

Is split as

"WWWWWWWWWWWWWWWWWWWW"

"WWWWWWWWWW WWWWWWWWWW"

Example 3:

"WWWWWWWWWW WWWWWWWWWW WWWWWWWWWWWWWWWWWWWW"

Is split as

"WWWWWWWWWW WWWWWWWWWW"

"WWWWWWWWWWWWWWWWWWWW"

Example 4:

"WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW"

Is split as

"WWWWWWWWWWWWWWWWWWWW"

"WWWWWWWWWWWWWWWWWWWW"

Hope this can help someone out there :)

CopperRabbit
  • 646
  • 3
  • 7
  • 24
1
function split_half($string){
$result= array();
$text = explode(' ', $string);
$count = count($text);
$string1 = '';
$string2 = '';
if($count > 1){
    if($count % 2 == 0){
        $start = $count/2;
        $end = $count;
        for($i=0; $i<$start;$i++){
            $string1 .= $text[$i]." ";
        }
        for($j=$start; $j<$end;$j++){
            $string2 .= $text[$j]." ";
        }           
    $result[] = $string1;
    $result[] = $string2;
    }
    else{
        $start = round($count/2)-1;
        $end = $count;
        for($i=0; $i<$start;$i++){
            $string1 .= $text[$i]." ";
        }
        for($j=$start; $j<$end;$j++){
            $string2 .= $text[$j]." ";
        }           
    $result[] = $string1;
    $result[] = $string2;

    }
}
else{
    $result[] = $string;
}
return $result;
}

Use this function to split string into half words..

1

As usual, regex spares the developer a lot of tedious string manipulation calls and unnecessary script bloat. I'll even go out on a limb and say that the regex pattern might be easier to understand that the string function laden scripts.

Code: (Demo)

$text = "The Quick : Brown Fox Jumped Over The Lazy / Dog";
$halfWay = (int)(strlen($text) / 2);
var_export(
    preg_split(
        '~.{0,' . $halfWay . '}\K\s~s',
        $text,
        2
    )
);

Output:

array (
  0 => 'The Quick : Brown Fox',
  1 => 'Jumped Over The Lazy / Dog',
)

Effectively, we calculate the center of the string by counting its characters, then dividing by two and removing any decimal places.

Then greedily match zero to $halfWay number of characters, then forget those characters with \K, then split the string on the latest qualifying space. The 3rd parameter of preg_split() determines the maximum amount of elements which may be produced.

mickmackusa
  • 43,625
  • 12
  • 83
  • 136
  • 1
    I like your solution, it can split to more parts too. Will split in 3 parts with not bad results too. – PeterM Jun 28 '21 at 22:24
0

I was created a great solution, where we dont lost characters or Where the word is not cut wrongly.

function split_title_middle ( $title ) {
    $title = strip_tags( $title );
    $middle_length = floor( strlen( $title ) / 2 );
    $new_title = explode( '<br />', wordwrap( $title, $middle_length, '<br />') );
    if (isset( $new_title[2] ) ) {
        $new_title[1] .= ' ' . $new_title[2];
        unset( $new_title[2] );
    }

    return $new_title;
 }

// how to use
$title = split_title_middle( $title );
echo $title[0] . '<strong>' . $title[1] . '</strong>';
Richelly Italo
  • 1,109
  • 10
  • 9
0

I tried using a couple of these answers but didn't get the best results so I thought I would share the solution. I wanted to split my titles in half and display one half white and one half green.

I ended up combining word count, the length of the text, the half way point and a third of the string. This allowed me to make sure the white section is going to be somewhere between the third way/half way mark.

I hope it helps someone. Be aware in my code -,& etc would be considered a word - it didn't cause me issues in my testing but I will update this if I find its not working as I hope.

public function splitTitle($text){

    $words = explode(" ",$text);
    $strlen = strlen($text);
    $halfwaymark = ceil($strlen/2);
    $thirdwaymark = ceil($strlen/3);

    $wordcount = sizeof($words);
    $halfwords = ceil($wordcount/2);
    $thirdwords = ceil($wordcount/3);

    $string1 ='';
    $wordstep = 0;
    $wordlength = 0;


    while(($wordlength < $wordcount && $wordstep < $halfwords) || $wordlength < $thirdwaymark){
        $string1 .= $words[$wordstep].' ';
        $wordlength = strlen($string1);
        $wordstep++;
    }

    $string2 ='';
    $skipspace = 0;
    while(($wordstep < $wordcount)){
        if($skipspace==0) {
            $string2 .= $words[$wordstep];
        } else {
            $string2 .= ' '.$words[$wordstep];
        }
        $skipspace=1;
        $wordstep++;
    }

    echo $string1.' <span class="highlight">'.$string2.'</span>';

}
-1

Just change the line:

$half = (int)ceil(count($words = (count(explode(" ",$text))) / 2);

str_word_count() may not count : or / as word.

Ariful Islam
  • 7,639
  • 7
  • 36
  • 54
  • Unfortunately this didn't work, it just created empty strings. Also it's missing a closing bracket at the end. But thanks for trying :) – Leo44 Nov 19 '11 at 08:53