jarvis Posted June 2, 2011 Share Posted June 2, 2011 Hi All, I hope someone can help. I use the below code to split content into 2 columns. Works a treat by finding the middle count of words and splitting. Problem is, sometimes it leaves the start of a line in one column and the rest in the other column. How can I alter the below to do what it does but find the start of a para as well to make it a neater split? God I hope that makes sense! Here's the code <?php $extract = str_replace("\r", "<br />", get_the_content('')); function splitMyText($colcontent, $columns) { $bodytext = array("$colcontent"); $text = implode(",", $bodytext); //prepare bodytext $length = strlen($text); //determine the length of the text $length = ceil($length/$columns); //divide length by number of columns $words = explode(" ",$text); // prepare text for word count and split the body into columns $c = count($words); $l = 0; for ($i=1;$i<=$columns;$i++) { $new_string = ""; $coloutput .= '<div class="column">'; for ($g=$l;$g<=$c;$g++) { if (strlen($new_string) <= $length || $i == $columns) $new_string.=$words[$g]." "; else { $l = $g; break; } } $coloutput .= $new_string; $coloutput .= "</div>"; } return $coloutput; } $columns = 2; echo splitMyText($extract, $columns); ?> Thanks Quote Link to comment Share on other sites More sharing options...
Adam Posted June 2, 2011 Share Posted June 2, 2011 The columns won't ever be equal, as it's unlikely the end of the paragraph will fall at the half-way point -- although in my opinion, if one column has to be longer it would make sense for it to be the first. I'd select the text up-to the middle character, and all after until the next new-line character. You can use regex to simplify this substantially: // First find the half-way point $length = strlen($str); $target = ceil($length / 2); // Use regex to match the characters from the start of the string to the target // point, and up until the next new-line character. Then also match any subsequent // characters separately... if (preg_match('/^(.{' . $target . '}[^\n]*)(.+)$/s', $str, $matches)) // { // Store $matches[1] and $matches[2] into more meanigful variables list( , $column1, $column2) = $matches; } Which you could display with some simple HTML like: <div class="article"> <div class="column1"> <?php echo nl2br($column1); ?> </div> <div class="column2"> <?php echo nl2br($column2); ?> </div> </div> Some formatting and trimming will be needed to prevent gaps at the start of column2. You should probably add an else statement to that IF, just in-case the regex doesn't work (say for 1 paragraph length articles). Also I only noticed after writing this, that you pass in a dynamic column number to your function.. If you only ever use 2 like your post suggested, then it's not a problem..? Quote Link to comment Share on other sites More sharing options...
WebStyles Posted June 2, 2011 Share Posted June 2, 2011 or you can figure out how many lines you have first, and then split accordingly: 1. split sentences into array using \n as delimiter 2. check each sentence length, to determine if they will occupy more than one line. Split sentences if needed 3. devide lines into columns Hope this helps Quote Link to comment Share on other sites More sharing options...
jarvis Posted June 2, 2011 Author Share Posted June 2, 2011 Thanks guys. @MrAdam where do I place the regex part in my code? I think I can sort of see how to use it but not quite sure - sorry ;-/ Quote Link to comment Share on other sites More sharing options...
Adam Posted June 2, 2011 Share Posted June 2, 2011 If you don't need more than 2 columns, and want to encapsulate it within a function, you can use this: function columiseText($str) { // First find the half-way point $length = strlen($str); $target = ceil($length / 2); // Use regex to match the characters from the start of the string to the target // point, and up until the next new-line character. Then also match any subsequent // characters separately... if (preg_match('/^(.{' . $target . '}[^\n]*)(.+)$/s', $str, $matches)) // { // Return matches[1] and matches[2] as an array return array($matches[1], $matches[2]); } return false; } Some usage examples: list($column1, $column2) = columiseText($article); // ... or ... $columns = columiseText($article); // $columns[0] contains column 1 // $columns[1] contains column 2 As I said if you want to support a dynamic number of columns, it's perfectly possible to do so with a bit more work on the function. Quote Link to comment Share on other sites More sharing options...
bartolix Posted October 26, 2012 Share Posted October 26, 2012 Hi Adam, thanks for post it I need help for n columns, please. Assuminf function should be function columiseText($str, $num-columns) I can not find solution in rest of function to return $columns array Quote Link to comment Share on other sites More sharing options...
Christian F. Posted October 26, 2012 Share Posted October 26, 2012 You could use array_shift () on $matches, and then just return it. If you only want to retrieve the second group (the .*? part), then just make the first group (the one with $target) a non-capturing one. Example of a non-capturing sub group: /(?:Find|Test) (.*?)\./ This will only return whatever follows "Find " or "Test ", up until the first period. Quote Link to comment Share on other sites More sharing options...
bartolix Posted October 26, 2012 Share Posted October 26, 2012 (edited) mmm... sorry, I post my code: function columiseText($text, $columns) { $length = strlen($text); $target = ceil($length / $columns); $i=1; if (preg_match('/^(.{' . $target . '}[^\n]*)(.+)$/s', $text, $matches)) { while ($i<=$columns) { $split[$i] = $matches[$i]; $i++; } return $split; } return false; } $columns=3; $article='Triskel Services is a reputable private security company successfully operating within the securities sector. We pride ourselves on both the quality of our services and our ethical approach designed to meet all of the requirements for private businesses. Our consultant teams include experts from various complementary backgrounds. All have experience in the private and public sectors. This diversity creates a synergy that allows us to operate efficiently as security consultants supplying security solutions and services to all. For our security operations we deploy highly skilled and experienced security teams, working to strict professional standards. All operations are designed to meet the individual’s requirements, ensuring minimum disruption to the daily routine of our customers. The diverse nationalities and multi-language skills combined with the competencies of our employees mean that we can deploy the most suitable task specific personnel to a variety of countries covering all possible circumstances.'; $cols = columiseText($article, $columns); echo "<div style='float:left; width:200px; margin-right:20px;'>".$cols[1]."</div>"; echo "<div style='float:left; width:200px; margin-right:20px;'>".$cols[2]."</div>"; echo "<div style='float:left; width:200px; margin-right:20px;'>".$cols[3]."</div>"; Edited October 26, 2012 by bartolix Quote Link to comment Share on other sites More sharing options...
Christian F. Posted October 26, 2012 Share Posted October 26, 2012 (edited) That code did not work at all, so I took the liberty to rewrite it for you. I've based my version on the multibyte string functions, to avoid mangling characters in case you get some text with characters occupying more than 1 byte. I've also approximated the cut-off points to a space, to that no words will be cut up either. The result: <?php /** * Splits a given text into the specified number columns, by the closest space from the cut-off point. * * @param string $text * @param int $columns * @param string $encoding * @return array */ function columiseText ($text, $columns, $encoding = 'UTF-8') { // Get the length of the article, and approximate cut points. $length = mb_strlen ($text, $encoding); $target = ceil ($length / $columns); // Set starting position and ready array for return values. $start = 0; $columns = array (); // While the string is not fully parsed. do { // Make sure the cut-off point is within the string. $stop = $target + $start - 1; if ($stop > $length) { // Get the remainder of the string. $stop = $length; } else { // Find the position of the first space before the cut position. $stop = mb_strpos ($text, ' ', $stop, $encoding) - $start; } // Cut the string at the specified point, and save it in the return array. $columns[] = trim (mb_substr ($text, $start, $stop, $encoding)); // Increase the start position for the next column. $start += $stop; } while ($start < $length); // Return the finished columns. return $columns; } $columns = 3; $article = 'Triskel Services is a reputable private security company successfully operating within the securities sector. We pride ourselves on both the quality of our services and our ethical approach designed to meet all of the requirements for private businesses. Our consultant teams include experts from various complementary backgrounds. All have experience in the private and public sectors. This diversity creates a synergy that allows us to operate efficiently as security consultants supplying security solutions and services to all. For our security operations we deploy highly skilled and experienced security teams, working to strict professional standards. All operations are designed to meet the individual’s requirements, ensuring minimum disruption to the daily routine of our customers. The diverse nationalities and multi-language skills combined with the competencies of our employees mean that we can deploy the most suitable task specific personnel to a variety of countries covering all possible circumstances.'; $cols = columiseText ($article, $columns); var_dump ($cols); This provided the following result: array(3) { [0]=> string(340) "Triskel Services is a reputable private security company successfully operating within the securities sector. We pride ourselves on both the quality of our services and our ethical approach designed to meet all of the requirements for private businesses. Our consultant teams include experts from various complementary backgrounds. All have" [1]=> string(345) "experience in the private and public sectors. This diversity creates a synergy that allows us to operate efficiently as security consultants supplying security solutions and services to all. For our security operations we deploy highly skilled and experienced security teams, working to strict professional standards. All operations are designed" [2]=> string(336) "to meet the individual’s requirements, ensuring minimum disruption to the daily routine of our customers. The diverse nationalities and multi-language skills combined with the competencies of our employees mean that we can deploy the most suitable task specific personnel to a variety of countries covering all possible circumstances." } Edited October 26, 2012 by Christian F. Quote Link to comment Share on other sites More sharing options...
bartolix Posted October 26, 2012 Share Posted October 26, 2012 Hi, thank you but It seems to have still problem... works fine with 1,2 or 3 colums but if I want 4 columns I get this error after some seconds... Fatal error: Allowed memory size of 134217728 bytes exhausted (tried to allocate 256 bytes) in... Quote Link to comment Share on other sites More sharing options...
Christian F. Posted October 26, 2012 Share Posted October 26, 2012 You need to go over your PHP scripts, and unset some of the unused variables I think. Especially for the huge objects, as you're currently using over 128 MB of RAM per page load! The code above was just the drop that caused the cup to flow over. Quote Link to comment Share on other sites More sharing options...
bartolix Posted October 26, 2012 Share Posted October 26, 2012 strange, because I run a page just with the code you posted Quote Link to comment Share on other sites More sharing options...
Christian F. Posted October 26, 2012 Share Posted October 26, 2012 (edited) This is the results of a test with me running the code above, only with 4 columns: $ php test.php array(4) { [0]=> string(258) "Triskel Services is a reputable private security company successfully operating within the securities sector. We pride ourselves on both the quality of our services and our ethical approach designed to meet all of the requirements for private businesses. Our" [1]=> string(255) "consultant teams include experts from various complementary backgrounds. All have experience in the private and public sectors. This diversity creates a synergy that allows us to operate efficiently as security consultants supplying security solutions and" [2]=> string(261) "services to all. For our security operations we deploy highly skilled and experienced security teams, working to strict professional standards. All operations are designed to meet the individual’s requirements, ensuring minimum disruption to the daily routine" [3]=> string(246) "of our customers. The diverse nationalities and multi-language skills combined with the competencies of our employees mean that we can deploy the most suitable task specific personnel to a variety of countries covering all possible circumstances." } Max memory used: 643488 Execution time: 0.0002131462097168 So I somewhat doubt that you executed the exact same code, especially since you said it takes several seconds. If you haven't added something extra to the code, then it's most likely the system which you're running it through. Thus the questions becomes: How does the code of entire file you're executing look like, and is this the very same file that you request PHP to parse (or is it included by another file)? Edited October 26, 2012 by Christian F. Quote Link to comment Share on other sites More sharing options...
bartolix Posted October 26, 2012 Share Posted October 26, 2012 Don't know... same code above: copy past, same error code with $columns=4; Quote Link to comment Share on other sites More sharing options...
bartolix Posted October 26, 2012 Share Posted October 26, 2012 Cristian... sorry You cool!! $article="..." not ='..' some ' inside text corrupted code thanks! You make me better night!!!! Quote Link to comment Share on other sites More sharing options...
bartolix Posted October 26, 2012 Share Posted October 26, 2012 just one more help... what's the way to divide column at '.' character? beforehand I thank you! Quote Link to comment Share on other sites More sharing options...
Christian F. Posted October 26, 2012 Share Posted October 26, 2012 Glad you got it sorted out, though by editing the text you didn't exactly run the same code. As for how to divide at a period, I'll leave that up to you to figure out. The code should be well commented, and quite easy to understand. Doing it yourself will help you understand what the code does, and thus reduce the amount of help you'll need in the future. PS: I made one mistake in the comments, writing "before" instead of "after". I apologize for that. Quote Link to comment Share on other sites More sharing options...
bartolix Posted October 27, 2012 Share Posted October 27, 2012 Thanks Cristian... you gave me so great help!! have a nice we! Quote Link to comment Share on other sites More sharing options...
bartolix Posted October 27, 2012 Share Posted October 27, 2012 trying to substitute ' ' search with '.' get problem with: mb_strpos ($text, ' ', $stop, $encoding) - $start; Something wrong with utf-8 encoding, It seems, and looking for in php-manual can't find solution Quote Link to comment Share on other sites More sharing options...
Christian F. Posted October 28, 2012 Share Posted October 28, 2012 Without stating what the problem is, in detail, or posting the changed code I'm afraid no-one can help. Remember that we don't know what you've done or what you're seeing on your screen, so we're depending upon you to be as accurate and complete in your descriptions as possible. That said, there are two things that needs to be done with the code above to make it split properly on periods. The first thing is that I've included the space (splitting character) at the start of the next line. So to get the period on the proper place, you'll need to increase the stopping position with one character. The other thing, is that periods are a whole lot less frequent than spaces, which means that the difference between the desired cutting position and the next period can be quite large. To combat that problem, you'll need to search both directions, and choose the one with the smaller difference. In other words, replace the else-block in the above code with this: // Find the positions of the first periods before and after the cut position. $stop_1 = mb_strpos ($text, '.', $stop, $encoding) - $start + 1; $stop_2 = mb_strrpos ($text, '.', ($stop+$start) - $length, $encoding) + 1; // Determine which cutting point is closest to desired length. if (($stop_1 - $start) - $target > $target - ($stop_2 - $start)) { $stop = $stop_2; } else { $stop = $stop_1; } Despite these changes you will notice a whole lot more variance in the column lengths, as opposed to the splitting on the space. Exactly how much depends upon the length of the sentences at the cut-off points. Quote Link to comment Share on other sites More sharing options...
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.