String parser/separation in PHP - 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?

Related

Exclude text to valid array

i have a text and i want convert it to array by exclude but i cant get true array
# SRC-ADDRESS DST-ADDRESS PACKETS BYTES SRC-USER DST-USER 0 10.40.47.48 216.58.205.211 12 822 2 1 10.40.47.48 102.132.97.21 66 9390 2 2 184.106.10.77 10.40.47.252 10 1819 1 3 10.40.47.252 104.27.155.225 1 41 1 4 10.40.47.252 144.76.103.6 5 878 1 5 102.132.97.35 10.40.47.252 11 1159 1 6 10.40.47.252 52.169.53.217 1 397 1 7 104.27.155.225 10.40.47.252 1 52 1
and i want result like this
Array
(
[0] => Array
(
[.id] => *0
[src-address] => 10.40.47.50
[dst-address] => 185.144.157.141
[packets] => 6
[bytes] => 1349
)
[1] => Array
(
[.id] => *1
[src-address] => 195.122.177.151
[dst-address] => 10.40.47.48
[packets] => 4
[bytes] => 174
[dst-user] => 2
)
....
i try this but it is wrong
$arr = exclude(" ",$text);
edit :
i can get text by another way
0 src-address=108.177.15.188 dst-address=10.40.47.252 packets=1 bytes=52 dst-user="1" 1 src-address=10.40.47.48 dst-address=172.217.19.150 packets=11 bytes=789 src-user="2" 2 src-address=184.106.10.77 dst-address=10.40.47.252 packets=26 bytes=5450 dst-user="1"
As I mentioned in the comments, one way would be to first explode your input by " " (space). You loop through each element/row of the resulting array. Then you explode each of those by = (equals sign). If the result of that explode is a single-element array, you know you should start a new row and create a key-value pair using your special .id key. If the count of the result is two, take the first part and make it the key of a new key-value pair in the current row, and take the second part and make it the value of that key-value pair.
There's a bit of a wrinkle in the fact that some of your source values are quoted, but you seem to want them not quoted in the result. To handle that we do a lose equality check on the value to see if it is the same when converted to an integer or not. If it is, then we convert it to remove the quotes.
$inputText = '0 src-address=108.177.15.188 dst-address=10.40.47.252 packets=1 bytes=52 dst-user="1" 1 src-address=10.40.47.48 dst-address=172.217.19.150 packets=11 bytes=789 src-user="2" 2 src-address=184.106.10.77 dst-address=10.40.47.252 packets=26 bytes=5450 dst-user="1"';
$result = array();
$spaceParts = explode(" ", $inputText);
foreach($spaceParts as $part)
{
$subParts = explode("=", $part);
if(count($subParts) == 1)
{
$resultIndex = (isset($resultIndex) ? $resultIndex+1 : 0);
$result[$resultIndex] = array(".id" => "*".$part);
}
else if(count($subParts) == 2)
{
$result[$resultIndex][$subParts[0]] = ((int)$subParts[1] == $subParts[1] ? (int)$subParts[1] : $subParts[1]);
}
else
{
// unexpected, handle however you want
}
}
print_r($result);
DEMO
Try reading the string in using str_getcsv replacing the delimiter with whatever the string is delimited by.
var_dump(str_getcsv($input, ","));
Note the manual states that the delimiter must be one char long. If wanting a tab or multiple spaces you will need to look into the answer:
str_getcsv on a tab-separated file
str-getcsv php manual
Here is something that could work but I would recoment using the csv methods instead to read the data in . And it is unclear how your data should be actually mapped to header.
$header = "# SRC-ADDRESS DST-ADDRESS PACKETS BYTES SRC-USER DST-USER ";
$input = "# SRC-ADDRESS DST-ADDRESS PACKETS BYTES SRC-USER DST-USER 0 10.40.47.48 216.58.205.211 12 822 2 1 10.40.47.48 102.132.97.21 66 9390 2 2 184.106.10.77 10.40.47.252 10 1819 1 3 10.40.47.252 104.27.155.225 1 41 1 4 10.40.47.252 144.76.103.6 5 878 1 5 102.132.97.35 10.40.47.252 11 1159 1 6 10.40.47.252 52.169.53.217 1 397 1 7 104.27.155.225 10.40.47.252 1 52 1 ";
$string = str_replace($header, "", $input );
$delimiter = " ";
$columns = 6;
$splitData = explode($delimiter, $string);
$result = [];
$i= 0;
foreach ($splitData as $key => $value) {
$result[$i][] = $value;
if (($key+1) % $columns == 0 ){
$i++;
}
}
var_dump($result);
Using the second example with the 0 src-address=108.177.15.188 dst-address=10.40.47.252 packets=1 bytes=52 dst-user="1" format, there are 6 entries:
$result = array_map(function($v) {
parse_str("id=".implode("&", $v), $output);
return $output;
}, array_chunk(explode(' ', $text), 6));
Explode the array on spaces
Chunk the array into 6 entries per element
Map to a function that implodes each array on & and parse it as a query string

preg_split regex - need to split user input around mathematical operators

I need to split a given user string into an array based around mathematical operators. The symbols I need the string splitting around are:
+
-
/
*
()
However I would like to expand on the regex to include other operators I will be adding into my program.
The regex I have so far is this:
"((\(|\d+.+|-|\*|\/\d+\|))"
which when ran through regex101.com matches a given input string of:
(30*30)/(9+8) with '30*30)/(9+8)
I would like the output to be similar to this:
[0] =
[1] = (
[2] = 30
[3] = *
[4] = 30
[5] = )
or:
[0] =
[1] = 4
[2] = *
[3] = 4
depending on whether brackets are present in the user string or not.
I forgot to include current results of the current regex string:
using http://www.phpliveregex.com/ to test preg-split with an input string of:
(30*30)+(9*8)
the result:
array(3
0 =>
1 =>
2 =>
)
Is this the pattern you are looking for?
preg_match_all("/(\(|-\d+|\d+|-|\+|\/|\*|\))/", $input, $output);
https://regex101.com/r/acKW27/3
Preg_match_all: http://www.phpliveregex.com/p/l7L
I forgot / in the regex. Links updated also.
preg_split() retains the delimiters by using the PREG_SPLIT_DELIM_CAPTURE flag. Include the additional flag PREG_SPLIT_NO_EMPTY to eliminate any empty elements. Here is an improved answer that will handle your sample input data, as well as floats and negative numbers.
Code: (Demo)
$expression = '-1*(2/(3+4)--10*-110.5/0.009+-.1)';
var_export(
preg_split(
'~(-?\d*(?:\.\d+)?|[()*/+-])~',
$expression,
0,
PREG_SPLIT_NO_EMPTY | PREG_SPLIT_DELIM_CAPTURE
)
);
Output:
array (
0 => '-1',
1 => '*',
2 => '(',
3 => '2',
4 => '/',
5 => '(',
6 => '3',
7 => '+',
8 => '4',
9 => ')',
10 => '-',
11 => '-10',
12 => '*',
13 => '-110.5',
14 => '/',
15 => '0.009',
16 => '+',
17 => '-.1',
18 => ')',
)
*Note, my above pattern makes digits before the decimal optional. If you know that your floats will always have a number before the dot, then you can use this pattern:
~(-?\d+(?:\.\d+)?|[()*/+-])~
The advantages are: no empty matches, no need for PREG_SPLIT_NO_EMPTY, and improved pattern efficiency.

PHP - array filled with stdin integer input

Example :
$_fp = fopen("file.txt", "r");
/* STDIN = "4 7 6 24 1"; */ <== user input
$input[] = fgets($_fp);
print_r($input);
OUTPUT :
Array
(
[0] => 4 7 6 24 1
)
Desired OUTPUT :
Array
(
[0] => 4
[1] => 7
[2] => 6
[3] => 24
[4] => 1
)
Is there any method to remove spaces from integer input after entering each to an array?
In a way to avoid having the whole input as one single line.
i used $input[] = explode(' ', trim(fgets($_fp))); now when there is second line it only puts the first line of the STDIN i need to read all lines and put them into the input variable
while($f = fgets(STDIN)){ echo "line: $f"; } is great use here
it is fine for echoing all lines but cant assign each line to a variable or array yet.. not sure if i should array_push() since i need 2 lines as variables and rest as arrays..
use trim remove the "\n" of the line, the use explode to convert it to array.
Live Demo
$input = explode(' ', trim(fgets($_fp)));
if you has more lines, use below:
$input[] = explode(' ', trim(fgets($_fp)));
Even we can try preg_match_all with regx also give same result with all cases like what if you have double space or any text between the interger strings
$string = "4 7 6 24 1";
$string = "4 test df 7 6 24 1";
$string = "4 7 6 24 1";
preg_match_all('!\d+!', $string, $matches);
print_r($matches);

Split file up based on delimiters in php - which is the best to use?

I am trying to parse a file using php but I am not sure of the best way to do it. The file consists of stuff like:
saturn+5 57 space+shuttle 34 gemini 12 mercury 2 soyuz+tm 1
What I'm trying to do is split it up and populate a hash map, so..
$inventory["saturn+5"] = "57";
$inventory["space+shuttle"] = "34";
and so on.
I don't know how to tackle this.
I am trying to write a bit of regex to process the file to separate out the fields but I'm not having much luck and was wondering if I should try using a different approach using split() or explode().
Here's my approach using regular expression.
$data = 'saturn+5 57 space+shuttle 34 gemini 12 mercury 2 soyuz+tm 1';
$inventory = array();
preg_match_all('/(\S+) (\S+)/', $data, $matches);
foreach ($matches[1] as $index => $match) {
$inventory[$match] = $matches[2][$index];
}
print_r($inventory);
Output
Array
(
[saturn+5] => 57
[space+shuttle] => 34
[gemini] => 12
[mercury] => 2
[soyuz+tm] => 1
)
my crude approach:
<?php
echo '<pre>';
$str="saturn+5 57 space+shuttle 34 gemini 12 mercury 2 soyuz+tm 1";
//break it on space
$e=explode(' ',$str);
//reindex array to start from 1
array_unshift($e, "phoney");
unset($e[0]);
print_r($e);
$inventory=array();
foreach ($e as $k=>$v){
//detects odd key
if(($k+2)%2==1) {
$inventory[$v]= $e[$k+1];
}
}
print_r($inventory);
demo: http://codepad.viper-7.com/PN6K8m
output:
Array
(
[saturn+5] => 57
[space+shuttle] => 34
[gemini] => 12
[mercury] => 2
[soyuz+tm] => 1
)
It's actually quite trivial with a regex:
preg_match_all("/ ([\w+]+) \s (\d+) /x", $string, $m);
$assoc = array_combine($m[1], $m[2]);
You're just looking for a combination of alphanumeric characters \w and optional + signs, then a space, then a \d decimal.
array_combine will give you the associative array.
If it's always in that order, this will work:
<?
$foo = 'saturn+5 57 space+shuttle 34 gemini 12 mercury 2 soyuz+tm 1';
$foo_array = preg_split('/\s+/', $foo);
$hash = array();
for ($i = 0; $i < count($foo_array); $i++){
$i % 2 ? null : $hash[$foo_array[$i]] = $foo_array[++$i];
}
print_r($hash);
?>
Output:
php foo.php
Array
(
[saturn+5] => 57
[space+shuttle] => 34
[gemini] => 12
[mercury] => 2
[soyuz+tm] => 1
)

Extracting string with regexp

In a text file, I have the folowing strings :
ID | LABEL | A | B | C
--------------------------------------
9999 | Oxygen Isotopes | | 0.15 | 1
8733 | Enriched Uranium | | 1 | 1
I would like to extract the fields ID and LABEL of each line using regular expression.
How I can achieve it ?
I am not certain why you insisted on regex.
As the column appear to be separated by | symbol, it seems like using PHP function explode would be an easier solution.
You would be able loop through the lines, and refer to each column using typical array index notation, for example: $line[0] and $line[1] for ID and LABEL respectively.
I doubt regex is the best solution here.
Try this to separate the text file into an array of lines (this might or might not work, depending on the OS of the machine you created the txt file on)
$lines = explode($text, "\n");
$final_lines = array();
foreach ($lines as $line) {
$parts = explode($line, " | ");
$final_lines[] = $parts;
}
Now you can access all of the data through the line number then the column, like
$final_lines[2][0]
Will contain 8733.
You could use preg_split on every line:
$array = preg_split(`/\s*\|\s*/`, $inputLine, 2);
Then as in djdy's answer, the ID will be in $array[0] and the label in $array[1].
No regex needed:
<?php
$file = file('file.txt');
$ret = array();
foreach($file as $k=>$line){
if($k<2){continue;}
list($ret['ID'][],
$ret['LABEL'][],
$ret['A'][],
$ret['B'][],
$ret['C'][]) = explode('|',$line);
}
print_r($ret);
//Label: Oxygen Isotopes ID:9999
echo 'Label: '.$ret['LABEL'][0].' ID:'.$ret['ID'][0];
/*
Array
(
[C] => Array
(
[0] => 1
[1] => 1
)
[B] => Array
(
[0] => 0.15
[1] => 1
)
[A] => Array
(
[0] =>
[1] =>
)
[LABEL] => Array
(
[0] => Oxygen Isotopes
[1] => Enriched Uranium
)
[ID] => Array
(
[0] => 9999
[1] => 8733
)
)
*/
?>
Regular expressions might not be the best approach here. I'd read in each line as a string, and use String.explode("|", input) to make an array of strings. The 0 index is your ID, the 1 index is your label, and so on for A, B, and C if you want. That's a more robust solution than using regex.
A regular expression that gets the ID might be something like
\d{4} |
You could do something similar for the label field, bug again, this isn't as robust as just using explode.
Though its not a best approach to use regular expression here but one may be like this
preg_match_all("/(\d{4}.?)\|(.*?)\|/s", $data, $matchs)
2nd and 3rd index of $matches will carry the required data
Try
$str = file_get_contents($filename);
preg_match_all('/^\s*(\d*)\s*\|\s*(.*?)\s*\|/m', $str, $matches);
// $matches[1] will have ids
// $matches[2] will have labels

Categories