Split a comma separated string but only split by a comma - php

Hi I have a long string
0BV,0BW,100,102,108,112,146,163191,192,193,1D94,19339,1A1,1AA,1AE,1AFD,1AG,1AKF.......
I want to show it in a page by sub sting them
like
0BV,0BW,100,102,108,112,146
163191,192,193,1D94,19339
1A1,1AA,1AE,1AFD,1AG,1AKF
What i want to do is create sub strings from the string , length of 100 characters , but if the 100 th character is a not a comma i want to check the next comma in the string and split by that .
I tried to use chunk() to split by word count , but since the sub-string lengths are different , it is showing inappropriate in the page
$db_ocode = $row["option_code"];
$exclude_options_array = explode(",",$row["option_code"]);
$exclude_options_chunk_array = array_chunk($exclude_options_array,25);
$exclude_options_string = '';
foreach($exclude_options_chunk_array as $exclude_options_chunk)
{
$exclude_options_string .= implode(",",$exclude_options_chunk);
$exclude_options_string .= "</br>";
}
Please help . thanks in advance

Take the string, set the cutoff position. If that position does not contain a comma then find the first comma after that position and cut off there. Simple
<?php
$string="0BV,0BW,100,102,108,112,146,163191,192,193,1D94,19339,1A1,1AA,1AE,1AFD";
$cutoff=30;
if($string[$cutoff]!=",")
$cutoff=strpos($string,",",$cutoff);
echo substr($string,0,$cutoff);
Fiddle

(.{99})(?=,),|([^,]*),
Instead of split you can grab the captures which is much easy.See demo for 20 characters.
https://regex101.com/r/sH8aR8/37

Using Hanky Panky's answer i was able to provide a complete solution to my Problem , Thank you very much Hanky panky . If my code is not efficient ,Kindly please edit it .
$string="0BV,0BW,100,102,108,112,146,163191,192,193,1D94,19339,1A1,1AA,1AE,1AFD";
for($start=0;$start<strlen($string);) {
$cutoff=30;
if(isset($string[$start+$cutoff]) && $string[$start+$cutoff]!=",")
{
$cutoff=strpos($string,",",$start+$cutoff);
}
else if(($start+$cutoff) >= strlen($string))
{
$cutoff = strlen($string);
}
else if($start >= 30)
{
$cutoff = $start + $cutoff;
}
echo substr($string,$start,$cutoff-$start)."\n";
$start=$cutoff+1;
}

In case python
ln=0
i=1
str='0BVAa,0BW,100,102,108,112,146,163191,192,193,1D94,19339,1A1,1AA,1AE,1AFD,1AG,1AKF'
for item in str:
print (item),
ln=ln+len(item)
if ln/10>=i and item==',':
print ""
i=i+1

Related

Increment Letter Number Combination

I came across this post (How to increment alphanumeric string with just lower case letters and numbers in PHP?) but my understanding of php is not this advanced.
I want to produce an output for the following combination of letters and numbers:
AA1AA1), incrementing from the right (AA1AA2) etc, then cycling through the letters (AA1AB1), etc all the way to ZZ0ZZ0.
Any assistance would be greatly appreciated!
UPDATE
I understand that this will output a total of 45 million combinations, but the plan is to create a form to populate ranges. AA1AA1 - AA1AB1 -> SUBMIT. So I was just looking for assistance with the code to do the increment and the rest I will try and figure out.
Thank you!
RESULTS
$field_start = "AA0AA0";
$field_end = "AA0AB2";
for ($value = $field_start; $value <= $field_end; $value++) {
echo $value . " <br />";
}
Outputs:
AA0AA0
AA0AA1
AA0AA2
AA0AA3
AA0AA4
AA0AA5
AA0AA6
AA0AA7
AA0AA8
AA0AA9
AA0AB0
AA0AB1
AA0AB2
Using the basic increment operator ++ will account for the various overflow and icrementing if a string with characters and numbers. So something like
$start = 'AA1AA1';
while ( $start != 'AA1AD2') {
echo ($start++)." ";
}
will output
AA1AA1 AA1AA2 AA1AA3 AA1AA4 AA1AA5 AA1AA6 AA1AA7 AA1AA8 AA1AA9 AA1AB0 AA1AB1

PHP - get total number of array items with a specific number sequence in value

So, basically I'm trying to count the number of landline phone numbers in a list of both landlines and mobile phone numbers $mobile_list (071234567890,02039989435,0781...)
$mobile_array = explode(",",$mobile_list); // turn into an array
$landlines = array_count_values($mobile_array); // create count variable
echo $landlines["020..."]; // print the number of numbers
So, I get the basic count specific elements function, but I don't see where I can specify if an element 'starts with' or 'contains' a sequence. With the above you can only specify an exact phone number (obviously not useful).
Any help would be great!
I don't see any reason to first explode the string to an array, and then check each array item.
That is a complete waste of performance!
I suggest using preg_match_all and match with word boundary "020".
That means the "word" has to start with 020.
$mobile_list = "071234567890,02039989435,0781,020122,123020";
preg_match_all("/\b020\d+\b/", $mobile_list, $m);
var_dump($m);
echo count($m[0]); // 2
https://3v4l.org/ucSDm
The lightest and fastest method I have found is to explode on ",020".
The array that is returned has item 0 as undefined, meaning we don't know if it's a 020 number so I have to look at that manually.
$temp = explode(",020", $mobile_list);
$cnt = count($temp);
if(substr($temp[0],0,3) != "020") $cnt--;
echo $cnt;
A small scale test shows this as the fastest method.
https://3v4l.org/rD54d
You can use array_reduce() to count the occurrences of strings beginning with '020'
$mobile_list = "02039619491,07143502893,02088024526,07351261813,02095694897";
$mobile_array = explode(',', $mobile_list);
function landlineCount($carry, $item)
{
if (substr($item, 0, 3) === '020') {
return $carry += 1;
}
return $carry;
}
$count = array_reduce($mobile_array, 'landlineCount');
echo $count;
prints 3
I'm sure the OP has finished what they needed to do hours ago but for fun here is a faster way to count the landlines.
I hadn't spotted that the question original code was exploding the string.
That isn't necessary, you can just count the sub strings with substr_count() this could miss the first which wouldn't have a comma before it so I check for that too with substr().
If you need the total count of all numbers you can just count the commas with substr_count() again and add one.
$count = substr($mobile_list, 0, 3) === '020' ? 1 : 0;
$count += substr_count($mobile_list, ",020");
$totalCount = substr_count($mobile_list, ",") + 1;
echo $count;
echo $totalCount;
Here is the bench run a 1000 times to get an average.
https://3v4l.org/Sma66
Use array_filter() or preg_grep() functions to find all numbers that contain or starts with given number sequence.
Note: There is easier and better solution in other answers that cover request to find values that start with given number sequence.
Because you have mentioned - "but I don't see where I can specify if an element 'starts with' or 'contains' a sequence." - My code assumes that you wan't to find any occurrence of sequence, not only in start of string of each item.
$mobile_list = '02000, 02032435, 039002300, 00305600';
$mobile_array = explode(",",$mobile_list); // turn into an array
$landlines = array_count_values($mobile_array); // create count variable
$sequence = '020'; // print the number of numbers
function filter_phone_numbers($mobile_array, $sequence){
return array_filter($mobile_array, function ($item) use ($sequence) {
if (stripos($item, $sequence) !== false) {
return true;
}
return false;
});
}
$filtered_items = array_unique (filter_phone_numbers($mobile_array, $sequence)); //use array_unique in case we find same number that both contains or starts with sequence
echo count($filtered_items);
Or with preg_grep():
$mobile_list = '02000, 02032435, 039002300, 00305600';
$mobile_array = explode(",",$mobile_list); // turn into an array
$landlines = array_count_values($mobile_array); // create count variable
$sequence = preg_quote('020', '~'); ; // print the number of numbers
function grep_phone_numbers($mobile_array, $sequence){
return preg_grep('~' . $sequence . '~', $mobile_array);
}
//use array_unique in case we find same number that both contains or starts with sequence
$filtered_items = array_unique(grep_phone_numbers($mobile_array, $sequence));
echo count($filtered_items);
I recommend doing this with the database. The database is design to manage data and can do it a lot more efficient than PHP can. You can simply put it into a query and just get the result you want in 1 go:
SELECT * FROM phone_numbers WHERE number LIKE '020%'
If you get the data from the database anyways, that LIKE adds a little time to the query, but less that it takes PHP to loop, strpos and store the results. Also, as you return a smaller dataset, less resources are being used.

Split a long string not using space

If I have sentences like this:
$msg = "hello how are you?are you fine?thanks.."
and I wish to seperate it into 3 (or whatever number).
So I'm doing this:
$msglen = strlen($msg);
$seperate = ($msglen /3);
$a = 0;
for($i=0;$i<3;$i++)
{
$seperate = substr($msg,$a,$seperate)
$a = $a + $seperate;
}
So the output should be..
hello how are
[a space here->] you?are you [<-a space here]
fine?thanks..
So is it possible to separate at middle of any word instead of having a space in front or end of the separated message?
Such as "thank you" -> "than" and "k you" instead of "thank" " you ".
Because I'm doing a convert function and with a space in front or end it will effect the convertion , and the space is needed for the conversion,so I can't ignore or delete it.
Thanks.
I take it you can't use trim because the message formed by the joined up strings must be unchanged?
That could get complicated. You could make something that tests for a space after the split, and if a space is detected, makes the split one character earlier. Fairly easy, but what if you have two spaces together? Or a single lettered word? You can of course recursively test this way, but then you may end up with split strings of lengths that are very different from each other.
You need to properly define the constraints you want this to function within.
Please state exactly what you want to do - do you want each section to be equal? Is the splitting in between words of a higher priority than this, so that the lengths do not matter much?
EDIT:
Then, if you aren't worried about the length, you could do something like this [starting with Eriks code and proceeding to change the lengths by moving around the spaces:
$msg = "hello how are you?are you fine?thanks..";
$parts = split_without_spaces ($msg, 3);
function split_without_spaces ($msg, $parts) {
$parts = str_split(trim($msg), ceil(strlen($msg)/$parts));
/* Used trim above to make sure that there are no spaces at the start
and end of the message, we can't do anything about those spaces */
// Looping to (count($parts) - 1) becaause the last part will not need manipulation
for ($i = 0; $i < (count($parts) - 1) ; $i++ ) {
$k = $i + 1;
// Checking the last character of the split part and the first of the next part for a space
if (substr($parts[$i], -1) == ' ' || $parts[$k][0] == ' ') {
// If we move characters from the first part to the next:
$num1 = 1;
$len1 = strlen($parts[$i]);
// Searching for the last two consecutive non-space characters
while ($parts[$i][$len1 - $num1] == ' ' || $parts[$i][$len1 - $num1 - 1] == ' ') {
$num1++;
if ($len1 - $num1 - 2 < 0) return false;
}
// If we move characters from the next part to the first:
$num2 = 1;
$len2 = strlen($parts[$k]);
// Searching for the first two consecutive non-space characters
while ($parts[$k][$num2 - 1] == ' ' || $parts[$k][$num2] == ' ') {
$num2++;
if ($num2 >= $len2 - 1) return false;
}
// Compare to see what we can do to move the lowest no of characters
if ($num1 > $num2) {
$parts[$i] .= substr($parts[$k], 0, $num2);
$parts[$k] = substr($parts[$k], -1 * ($len2 - $num2));
}
else {
$parts[$k] = substr($parts[$i], -1 * ($num1)) . $parts[$k];
$parts[$i] = substr($parts[$i], 0, $len1 - $num1);
}
}
}
return ($parts);
}
This takes care of multiple spaces and single lettered characters - however if they exist, the lengths of the parts may be very uneven. It could get messed up in extreme cases - if you have a string made up on mainly spaces, it could return one part as being empty, or return false if it can't manage the split at all. Please test it out thoroughly.
EDIT2:
By the way, it'd be far better for you to change your approach in some way :) I seriously doubt you'd actually have to use a function like this in practice. Well.. I hope you do actually have a solid reason to, it was somewhat fun coming up with it.
If you simply want to eliminate leading and trailing spaces, consider trim to be used on each result of your split.
If you want to split the string into exact thirds it is not known where the cut will be, maybe in a word, maybe between words.
Your code can be simplified to:
$msg = "hello how are you?are you fine?thanks..";
$parts = str_split($msg, ceil(strlen($msg)/3));
Note that ceil() is needed, otherwise you might get 4 elements out because of rounding.
You're probably looking for str_split, chunk_split or wordwrap.

Get the two most frequent words within several strings

I have a list of phrases and I want to know which two words occurred the most often in all of my phrases.
I tried playing with regex and other codes and I just cannot find the right way to do this.
Can anyone help?
eg:
I am purchasing a wallet
a wallet for 20$
purchasing a bag
I'd know that
a wallet occurred 2 times
purchasing a occurred 2 times
<?
$string = "I am purchasing a wallet a wallet for 20$ purchasing a bag";
//split string into words
$words = explode(' ', $string);
//make chunks block ie [0,1][2,3]...
$chunks = array_chunk($words, 2);
//remove first array element
unset($words[0]);
//make chunks block ie [0,1][2,3]...
//but since first element is removed , the real block will be [1,2][3,4]...
$alternateChunks = array_chunk($words, 2);
//merge both chunks
$totalChunks = array_merge($chunks,$alternateChunks);
$finalChunks = array();
foreach($totalChunks as $t)
{
//change the inside chunk to pharse using +
//+ can be replaced to space, if neeced
//to keep associative working + is used instead of white space
$finalChunks[] = implode('+', $t);
}
//count the words inside array
$result = array_count_values($finalChunks);
echo "<pre>";
print_r($result);
I hesitate to suggest this, as it's an extremely brute force way to go about it:
Take your string of words, explode it using the explode(" ", $string); command, then run it through a for loop checking every two word combination against every two words in the string.
$string = "I am purchasing a wallet a wallet for 20$ purchasing a bag";
$words = explode(" ", $string);
for ($t=0; $t<count($string); $t++)
{
for ($i=0; $i<count($string); $i++)
{
if (($words[$t] . words[$t+1]) == ($words[$i] . $word[$i+1])) {$count[$words[$i].$words[$i+1]]++}
}
}
So the nested for loop steps in, grabs the first two words, compares them to each other set of two consecutive words, then grabs the next two words and does it again. Every answer will have an answer of at least 1 (it will always match itself) but sorting the resulting array by size will give you the most repeated values.
Note that this will run (n-1)*(n-1) iterations, which could get unwieldy FAST.
Place them all into an array, and access them by the current word index and next word index.
I think this should do the trick. It will grab pairs of words, unless you are at the end of the string, where you'll get only one word.
$str = "I purchased a wallet because I wanted a wallet a wallet a wallet";
$words = explode(" ", $str);
$array_results = array();
for ($i = 0; $i<count($words); $i++) {
if ($i < count($words)-1) {
$pair = $words[$i] . " " . $words[$i+1]; echo $pair . "\n";
// Have to check if the key is in use yet to avoid a notice
$array_results[$pair] = isset($array_results[$pair]) ? $array_results[$pair] + 1 : 1;
}
// At the end of the array, just use a single word
else $array_results[$words[$i]] = isset($array_results[$words[$i]]) ? $array_results[$words[$i]] + 1 : 1;
}
// Sort the results
// use arsort() instead to get the highest first
asort($array_results);
// Prints:
Array
(
[I wanted] => 1
[wanted a] => 1
[wallet] => 1
[because I] => 1
[wallet because] => 1
[I purchased] => 1
[purchased a] => 1
[wallet a] => 2
[a wallet] => 4
)
Update changed ++ to +1 above since it wasn't working when tested...
Try to put it with explode into an array and count the values with array_count_values.
<?php
$text = "whatever";
$text_array = explode( ' ', $text);
$double_words = array();
for($c = 1; $c < count($text_array); $c++)
{
$double_words[] = $text_array[$c -1] . ' ' . $text_array[$c];
}
$result = array_count_values($double_words);
?>
I updated it now to two word version. Does this work for you?
array(9) {
["I am"]=> int(1)
["am purchasing"]=> int(1)
["purchasing a"]=> int(2)
["a wallet"]=> int(2)
["wallet a"]=> int(1)
["wallet for"]=> int(1)
["for 20$"]=> int(1)
["20$ purchasing"]=> int(1)
["a bag"]=> int(1)
}
Since you used the excel tag, I thought I'd give it a shot, and it's actually really easy.
Split string using space as delimiter. Data > Text to Columns... > Delimited > Delimiter: Space. Each word is now in its own cell.
Transpose the result (not strictly required but much easier to visualize). Copy, Edit > Paste Special... > Transpose.
Make cells containing consecutive word pairs. So if your words are in cells B5:B15, cell C5 should be =B5&" "&B6 (and drag down).
Count occurence of each word pair: In cell D5, =COUNTIF($C$5:$C$15,"="&C5), drag down.
Highlight the winner(s). Select C5:D15, Format > Conditional Formatting... > Formula Is =$D5=MAX($D$5:$D$15) and choose e.g. a yellow background.
Note that there is some inefficiency in step 4 because the count of each word pair will be calculated multiple times if that word pair occurs multiple times. If this is a concern, then you can first make a list of unique word pairs using Data > Filter > Advanced Filter... > Unique records only.
An automated VBA solution could easily be crafted by recording a macro of the above followed by some minor editing.
One way to go about it is to use SPLIT or a regex to split the sentences into words and store each into an array. Then take the array and create a dictionary object. When you add a term to the dictionary, if it's already there, add 1 to the .value to tally the count.
Here is some example code (far from perfect as it's just to show the overlying concept) that will take all the string in column A and generate a word frequency list in columns B and C. It's not exactly what you want, but should give you some ideas on how you can go about doing it I hope:
Sub FrequencyList()
Dim vArray As Variant
Dim myDict As Variant
Set myDict = CreateObject("Scripting.Dictionary")
Dim i As Long
Dim cell As range
With myDict
For Each cell In range("A1", cells(Rows.count, "A").End(xlUp))
vArray = Split(cell.Value, " ")
For i = LBound(vArray) To UBound(vArray)
If Not .exists(vArray(i)) Then
.Add vArray(i), 1
Else
.Item(vArray(i)) = .Item(vArray(i)) + 1
End If
Next
Next
range("B1").Resize(.count).Value = Application.Transpose(.keys)
range("C1").Resize(.count).Value = Application.Transpose(.items)
End With
End Sub

Splitting string on spaces but allow a space in 1 field using regex

This is kind of a follow on from this post: Regex for splitting params out using preg_match
I have this string 1 0 61 12345678 sierra007^7 0 0 123.123.123.123:524 26429 25000 and I need to get each element. It was suggested I use explode which was a great simple solution but now I need to allow spaces in one of the fields.
Someone else posted this regex:
/^([-0-9]+)\s+([-0-9]+)\s+([-0-9]+)\s+([-0-9]+)\s+(\S+)\s+([-0-9])\s+([-0-9]+)\s+([-0-9.:]+)\s+([-0-9.]+)\s+([-0-9.]+)/mx
That does everything else and I was wondering if it could be modified to allow spaces in field 5 (sierra007^7). The only advice I can offer is that the rest of the fields are always numeric (or a colon as you can see) before and after field 5. Is this possible with 1 regex statement or do I need to parse it in PHP and fudge it together?
EDIT: For example, field 5 could be sierra007^7 OR si erra007^7 or si er ra007^7. It would know that it came across field 5 as its the only one that contains a-zA-Z characters. It would know where field 5 ends because field 6 only contains 0-9 characters.
Thanks.
Why not use explode, like the other thread. And count the number of items in the array. If more items are in the array, you put item 5 + any number too high together again with implode..
Eg. your normal row has 10 items. If the resulting explode has 15 items, you:
implode(" ",array_slice($array,5,(count($array)-10)));
If the number of fields never changes, and there's always a value for each field, you can do it using code below:
$fields = explode (' ', $str);
$defaultNumFields = 10;
if (count($fields) > $defaultNumFields) {
for ($i = 5; $i < (count($fields) - $defaultNumFields) + 5; $i++) {
$field[4] .= ' '.$field[$i];
unset($field[$i]);
}
}
$fields = array_values($fields);
That should do it. I might have mis-calcuated and you might need to change the +4 to a +5, test it on a few strings and let me know.

Categories