How to parse to string to multidimensional array (regex?) - php

I need to pass the data to an array by blocks, how can I make this? Do I need to use regex? My script gives me errors because I can not separate it as I wish. Does anyone have any ideas?
Data:
~0
11111111
~1
222222222
~2
3333333333
~end
~0
aaaaaaaaaaa
~1
bbbbbbbbbb
~2
cccccccccc
~3
ddddddddddd
~end
~0
yyyyyyyyyyy
xxxxxxxx
ffffffffff
~1
rrrrrrrrrrrr
~end
I need it like this:
Array (
[0] => Array
(
[0] => 11111111
[1] => 222222222
[2] => 3333333333
)
),
[1] => Array
(
[0] => aaaaaaaaaaa
[1] => bbbbbbbbbb
[2] => cccccccccc
[3] => ddddddddddd
)
),
[2] => Array
(
[0] => yyyyyyyyyyy
xxxxxxxx
ffffffffff
[1] => rrrrrrrrrrrr
)
),
)
My code (Fail):
$texto = "~0
11111111
~1
222222222
~2
3333333333
~end
~0
aaaaaaaaaaa
~1
bbbbbbbbbb
~2
cccccccccc
~3
ddddddddddd
~end
~0
yyyyyyyyyyy
xxxxxxxx
ffffffffff
~1
rrrrrrrrrrrr
~end";
preg_match_all("/(?ms)^~0.*?~end/", $texto, $coincidencias);
foreach ( $coincidencias[0] as $bloque ){
preg_match_all("/\~.*\n/", $bloque, $sub_bloques);
$hola[] = $sub_bloques;
}

Here is one non-regex way: split the string into lines and iterate over them. Check for the conditions you've specified and add each line to a sub-array if it meets the conditions. Then when you get to an ~end line, append the sub-array to the main array.
$sub_bloques = [];
$hola = [];
foreach(array_map('trim', explode("\n", $texto)) as $line) {
if ($line && substr($line, 0, 1) !== '~') {
$sub_bloques[] = $line;
}
if ($line == '~end') {
$hola[] = $sub_bloques;
$sub_bloques = [];
}
}
For a regex solution, start by exploding on ~end to break the main text into sections, then preg_match_all on the sections to find lines that meet your conditions.
foreach (explode('~end', $texto, -1) as $section) {
preg_match_all('/\n *(?!~)(\w+)/', $section, $matches);
if ($matches[1]) $result[] = $matches[1];
}
(?!~) is a a negative lookbehind to exclude lines that start with ~. Maybe there's some way to do the whole thing with one big cool regex, but I'm not that good at it.

Because you want to have your sub-blocks separated into blocks in your output array, there needs to be two-steps in the method. The reason is that your sub-blocks have differing capture group counts and regex will not permit this variability.
Code:
// This delivers the sub-blocks in their relative blocks as requested in the OP
foreach (preg_split('/\s+~end\s*/',$texto) as $bloque) {
if(preg_match_all('/(?:\~\d+\s+)\K.+?(?:\s+\S+)*?(?=\s+\~|$)/',$bloque,$sub_bloques)){
$hola[]=$sub_bloques[0];
}
}
var_export($hola);
Output *reformatted/condensed to save space on this page (View Demo):
array(
array('11111111','222222222','3333333333'),
array('aaaaaaaaaaa','bbbbbbbbbb','cccccccccc','ddddddddddd'),
array('yyyyyyyyyyy
xxxxxxxx
ffffffffff','rrrrrrrrrrrr')
)
Alternatively, if you want to have all sub-blocks listed in a 1-dim array (not divided by blocks) the output array can be built in one step:
if(preg_match_all("/(?:\~\d+\s*)\K.+?(?:\s+\S+)*?(?=\s+\~)/s", $texto, $coincidencias)){
var_export($coincidencias[0]);
}
1-dim output:
array (
0 => '11111111',
1 => '222222222',
2 => '3333333333',
3 => 'aaaaaaaaaaa',
4 => 'bbbbbbbbbb',
5 => 'cccccccccc',
6 => 'ddddddddddd',
7 => 'yyyyyyyyyyy
xxxxxxxx
ffffffffff',
8 => 'rrrrrrrrrrrr',
)

Related

Get two words (numbers) around a certain text in a string

There's a certain contents (from a webpage) where I need to get two numbers of a certain list.
Basically the list goes like:
..... 10 from 12....
..... 1 from 20....
..... 20 from 100...
and so on. For me, I need to get these numbers surrounding the word "from", so I can perform certain calculations with them later.
I looked into this and tried different ways to perform it with strpos or strstr but nothing worked. Does anyone have any idea how to accomplish something like that?
$text = "..... 10 from 12 etc....
..... 1 from 20....
..... 20 from 100...";
$r = preg_match_all('~(\d+) *from *(\d+)~u',$text,$match, PREG_SET_ORDER);
var_export($match);
Output:
array (
0 =>
array (
0 => '10 from 12',
1 => '10',
2 => '12',
),
1 =>
array (
0 => '1 from 20',
1 => '1',
2 => '20',
),
2 =>
array (
0 => '20 from 100',
1 => '20',
2 => '100',
),
)
Explanations:
\d+ one digit or more
(\d+) the sequence in brackets -> the digits in the result array
* no, one or more spaces
from the word from
Here is an example of what you can do with explode:
<?php
/* the text with many different gaps and mess! */
$text = "wlfsdjf;sd sdfljsdfk kfgjdlg d 10 from 200 kflgjdkgdklgsd slfksjd
dfgdf fgdlkjdf d 20 from 30 ldk;lfsd
dflksdjf 40 from 50 dkf;sd sdjfs ";
/* main array */
$array = explode("\n",$text);
echo '<pre>';
print_r($array);
/* looping and clearing out our values per line */
foreach($array as $k => $line){
$f = explode(" ",explode(" from ",$line)[0]);
$f = array_pop($f);
$numbers[$k]['first'] = $f;
$s = explode(" ",explode(" from ",$line)[1]);
$s = $s[0];
$numbers[$k]['second'] = $s;
}
/* our new array set per line */
print_r($numbers);
Will return:
Array
(
[0] => wlfsdjf;sd sdfljsdfk kfgjdlg d 10 from 200 kflgjdkgdklgsd slfksjd
[1] => dfgdf fgdlkjdf d 20 from 30 ldk;lfsd
[2] => dflksdjf 40 from 50 dkf;sd sdjfs
)
Array
(
[0] => Array
(
[first] => 10
[second] => 200
)
[1] => Array
(
[first] => 20
[second] => 30
)
[2] => Array
(
[first] => 40
[second] => 50
)
)

php split / cluster binary into chunks based on next 1 in cycle

I need to figure out a method using PHP to chunk the 1's and 0's into sections.
1001 would look like: array(100,1)
1001110110010011 would look like: array(100,1,1,10,1,100,100,1,1)
It gets different when the sequence starts with 0's... I would like it to segment the first 0's into their own blocks until the first 1 is reached)
00110110 would look like (0,0,1,10,1,10)
How would this be done with PHP?
You can use preg_match_all to split your string, using the following regex:
10*|0
This matches either a 1 followed by some number of 0s, or a 0. Since a regex always tries to match the parts of an alternation in the order they occur, the second part will only match 0s that are not preceded by a 1, that is those at the start of the string. PHP usage:
$beatstr = '1001110110010011';
preg_match_all('/10*|0/', $beatstr, $m);
print_r($m);
$beatstr = '00110110';
preg_match_all('/10*|0/', $beatstr, $m);
print_r($m);
Output:
Array
(
[0] => Array
(
[0] => 100
[1] => 1
[2] => 1
[3] => 10
[4] => 1
[5] => 100
[6] => 100
[7] => 1
[8] => 1
)
)
Array
(
[0] => Array
(
[0] => 0
[1] => 0
[2] => 1
[3] => 10
[4] => 1
[5] => 10
)
)
Demo on 3v4l.org

How to keep the delimiter in the next item in preg_split?

I split a string by a set of characters as
$str = 'a-1 90 b55 0 -4 4 c9';
$array = preg_split('#(?<=[abc])#',$str, -1, PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY);
it preserves the delimiter in the previous element as (demo)
Array
(
[0] => a
[1] => -1 90 b
[2] => 55 0 -4 4 c
[3] => 9
)
but I want to keep it in the next item as
Array
(
[0] => a-1 90
[1] => b55 0 -4 4
[2] => c9
)
Use lookahead instead of lookbehind:
$str = 'a-1 90 b55 0 -4 4 c9';
$array = preg_split('#(?=[abc])#',$str, -1, PREG_SPLIT_NO_EMPTY);
print_r($array);
Since you're not using any capture group in your regex, therefore there is no need to use PREG_SPLIT_DELIM_CAPTURE flag.
Code Demo

How to split a string in multiple ones (Php)?

I want to split a big number/string for example 123456789123456789 into 6 smaller strings/numbers of 3 characters each. So the result would be 123 456 789 123 456 789. How can I do this?
Use chunk_split():
$var = "123456789123456789";
$split_string = chunk_split($var, 3); // 3 is the length of each chunk
If you want your result as an array, you can use str_split():
$var = "123456789123456789";
$array = str_split($var, 3); // 3 is the length of each chunk
You may use chunk_split() function.
It splits a string into smaller
$string = "123456789123456789";
echo chunk_split ($string, 3, " ");
will output
123 456 789 123 456 789
First parameter is the string to be chunked. The second is the chunk length and the third is what you want at the end of each chunk.
See PHP manual for further information
You could do something like this:
$string = '123456789123456789';
preg_match_all('/(\d{3})/', $string, $matches);
print_r($matches[1]);
Output:
Array
(
[0] => 123
[1] => 456
[2] => 789
[3] => 123
[4] => 456
[5] => 789
)
\d is a number and {3} is 3 of the previously found character (in this case a number.
....
or if there won't always be even groupings:
$string = '12345678912345678922';
preg_match_all('/(\d{1,3})/', $string, $matches);
print_r($matches[1]);
Output:
Array
(
[0] => 123
[1] => 456
[2] => 789
[3] => 123
[4] => 456
[5] => 789
[6] => 22
)
Demo: https://regex101.com/r/rX0pJ1/1

String parser/separation in PHP

I have data which I wish to be pasted into a textbox, it will be in the form E.G
Ryu Aiter D78:21:87:13 177 /177 1 / 6
Ryu Chronos D78:21:26:21 182 /182 0 / 6
Ryu Hermes D78:21:26:22 201 /201 0 / 6
Ryu Hefaistos D78:31:75:10 136 /136 1 / 2
Ryu Krotos D78:84:96:11 170 /170 1 / 6
Ryu Heros D78:65:51:31 175 /175 2 / 5
Ryu Arachnos D78:13:84:11 185 /185 0 / 5
its splits up like this
Base(max 16 chars)
Location(staring D , 12 chars)
econ/max econ (int/int)
used/Total(int/int)
What i wish to do is create a loop for each Row of text,
and then inside that loop chop out each part of the row into variables for each component.
as far as ideas on separating it i know that the : symbol is banned from names and bases.
so if i find the first ":" then step back 2 and take the next 12 chars that is my location
i know that can be done with a until loop and if(string[x]=':')
But how do i loops through rows?
And how can i separate the rest of the data in a row?
This is what regular expressions are for :P try this out:
$lines = explode( "\r\n", $data );
$users = array();
foreach( $lines as $line )
{
$matches = array();
$user = array();
preg_match( "/([^ ]+) ([^ ]+) ((?:[A-Z])(?:[0-9]+:){3}[0-9]+) ([0-9]+) \/([0-9]+) ([0-9]+) \/ ([0-9]+)/", $line, $matches );
list(,$user['name'],$user['base'],$user['location'],$user['econ'],$user['maxecon'],$user['used'],$user['total']) = $matches;
$users[] = $user;
}
You will have an array called users which contains a series of associative arrays with the components. Like below...
Array
(
[0] => Array
(
[total] => 6
[used] => 1
[maxecon] => 177
[econ] => 177
[location] => D78:21:87:13
[base] => Aiter
[name] => Ryu
)
[1] => Array
(
[total] => 6
[used] => 0
[maxecon] => 182
[econ] => 182
[location] => D78:21:26:21
[base] => Chronos
[name] => Ryu
)
etc, etc...
EDIT: I made a lot of assumptions about the data as you haven't given many details, if you need further help with the expression let me know.
UPDATE AS PER YOUR COMMENT:
Line 182: $name = htmlspecialchars(mysql_real_escape_string($_POST['name']));
Line 188: $tecon = htmlspecialchars(mysql_real_escape_string($user['econ']));
You should turn on display_errors as they were simple syntax errors that could easily be debugged.
Can you just use explode and gradually break it down?
eg.
explode the entry into seperate lines at '\n'
then explode each line into 2, everything before the 1st ':', and everything after
explode the 1st part into pieces using each 'space' to give you Name, Base, Location
explode the 2nd part using 'space', ':' or '/' to give you econ/max econ and used/Total
if(preg_match_all('/^([a-z]{1,16})\s+([a-z]{1,16})\s+(D\d+):(\d+):(\d+):(\d+)\s+(\d+)\s+\/(\d+)\s+(\d+)\s+\/\s+(\d+)$/mi', $yourinputgoeshere, $match) {
print_r($match);
}
This should, untested, get everything into a large array, separated. Untested
Extending the same idea i am trying to use preg match for a single line on another page.
i use the code
$data = $_POST['list'];
$matches = array();
$user = array();
preg_match( "/(.+?) ((?:[A-Z])(?:[0-9]+:){3}[0-9]+) ([0-9]+) \/([0-9]+) ([0-9]+) \/ ([0-9]+)/", $data, $matches );
list(,$user['base'],$user['location'],$user['econ'],$user['maxecon'],$user['used'],$user['total']) = $matches;
$base = $users['base'];
$location = $users['location'];
$tecon = $users['econ'];
i used echo to print out £data and it contains the data as expected but the same code without the lines loop does not seperate the parts of my data into the array..in fact the array size of $user remains empty, what has gone wroung?

Categories