php foreach preg_match'd line, get next lines - php
I hope the title is self explanatory.
I would like to loop over a xml file line by line, then match a particular line (getting attributes from that line), then get the next X lines after that line.
I have the following code, which attempts to do this, but I cant seem to figure out how to get the next X lines after.
$file = 'Electric.xml';
$lines = file($file);//file in to an array
foreach($lines as $line){
$reads = element_attributes('WINDOW',$line);
if($reads['class'] == 'Bracelets'){
print_r($reads);
}
if($reads['class'] == 'Handbags'){
print_r($reads);
}
}
function element_attributes($element_name, $xml) {
if ($xml == false) {
return false;
}
// Grab the string of attributes inside an element tag.
$found = preg_match('#<'.$element_name.
'\s+([^>]+(?:"|\'))\s?/?>#',
$xml, $matches);
if ($found == 1) {
$attribute_array = array();
$attribute_string = $matches[1];
// Match attribute-name attribute-value pairs.
$found = preg_match_all(
'#([^\s=]+)\s*=\s*(\'[^<\']*\'|"[^<"]*")#',
$attribute_string, $matches, PREG_SET_ORDER);
if ($found != 0) {
// Create an associative array that matches attribute
// names to attribute values.
foreach ($matches as $attribute) {
$attribute_array[$attribute[1]] =
substr($attribute[2], 1, -1);
}
return $attribute_array;
}
}
// Attributes either weren't found, or couldn't be extracted
// by the regular expression.
return false;
}
Use a proper parser, like SimpleXML, to parse the file. Then your issue becomes trivial. The PHP manual contains a tutorial to help you get started.
In this case you just loop over the lines, checking the property of the tag you're looking for, until you find a match. Then, loop over the next # elements, saving them into an array.
Something like this:
$xml = new SimpleXML ("file.xml");
foreach ($xml->node->element as $element) {
if ($element->attribute != "match") {
continue;
}
// If we get here we want to save the next # lines/elements.
}
$linesLength = count($lines);
$XLines = array();
for($index = 0; $index < $linesLength; $index++){
$reads = element_attributes('WINDOW',$line);
if($reads['class'] == 'Bracelets'){
print_r($reads);
$XLines[] = array_slice($array, $index, $X);
$index += $X;
}
if($reads['class'] == 'Handbags'){
print_r($reads);
$XLines[] = array_slice($array, $index, $X);
$index += $X;
}
}
Related
PHP get possible string combination of given array which match with given string
I have an array which contains bunch of strings, and I would like to find all of the possible combinations no matter how it's being sorted that match with given string/word. $dictionary = ['flow', 'stack', 'stackover', 'over', 'code']; input: stackoverflow output: #1 -> ['stack', 'over', 'flow'] #2 -> ['stackover', 'flow'] What I've tried is, I need to exclude the array's element which doesn't contain in an input string, then tried to match every single merged element with it but I'm not sure and get stuck with this. Can anyone help me to figure the way out of this? thank you in advance, here are my code so far <?php $dict = ['flow', 'stack', 'stackover', 'over', 'code']; $word = 'stackoverflow'; $dictHas = []; foreach ($dict as $w) { if (strpos($word, $w) !== false) { $dictHas[] = $w; } } $result = []; foreach ($dictHas as $el) { foreach ($dictHas as $wo) { $merge = $el . $wo; if ($merge == $word) { } elseif ((strpos($word, $merge) !== false) { } } } print_r($result);
For problems like this you want to use backtracking function splitString($string, $dict) { $result = []; //if the string is already empty return empty array if (empty($string)) { return $result; } foreach ($dict as $idx => $term) { if (strpos($string, $term) === 0) { //if the term is at the start of string //get the rest of string $substr = substr($string, strlen($term)); //if all of string has been processed return only current term if (empty($substr)) { return [[$term]]; } //get the dictionary without used term $subDict = $dict; unset($subDict[$idx]); //get results of splitting the rest of string $sub = splitString($substr, $subDict); //merge them with current term if (!empty($sub)) { foreach ($sub as $subResult) { $result[] = array_merge([$term], $subResult); } } } } return $result; } $input = "stackoverflow"; $dict = ['flow', 'stack', 'stackover', 'over', 'code']; $output = splitString($input, $dict);
looping through txt file to use specific part of a string
I am new to Php and can't seem to figure this out no matter how much I've googled. So I've opened the txt file (which consists of multiple lines of this type of string unique Identifier IMEI in bold: Rx:00:39:54 06/09/2015:+RESP:GTEPS,210101,863286020022449,,8296,01,1,3,0.0,0,1031.1,29.367950,-30.799161,20150906003710,,,,,,2857.9,20150906003710,8038$) There are different strings with different IMEIs but i only want to use a specific one. My question is, how do I extract/only use the string with the same Unique identifier and then loop through those to use in another function? My function has different cases and each case has different calculations, so I'll need to loop through the txt file (with e.g. 863286020022449 as Identifier, ignoring other identifiers/IMEIs) in order to use the string in my function as below: This is my starter function: function GetParam($unknownFunction, $numberCommas) { $returnString = ""; $foundSting = 0; $numberFound = 0; $len = strlen($unknownFunction); for ($i = 0; $i < $len; ++$i) { if ($Rawline[$i] == ",") { ++$numberFound; if ($numberFound > $numberCommas) break; if ($numberFound == $numberCommas) $foundSting = 1; } else if ($foundSting == 1) { $returnString .= $unknownFunction[$i]; } } return $returnString; echo $returnString; } $i = strpos($unknownFunction, ":GT"); $p = substr($unknownFunction, $i+3,3); $Protocol = GetParam($unknownFunction, 1); //this switch reads the differences in the message types (e.g. HBD- in this case is a heartbeat message type and would thus have a different amount of commas in the string and has different definitions of the characters within the commas) switch ($p) { case 'HBD': //+ACK:GTHBD,220100,135790246811220,,20100214093254,11F0$ //This is an example of an HBD message $result2["Type"] = 'Heart beat'; $IMEI = GetParam($unknownFunction, 2); $mDate = GetParam($unknownFunction, 4); $mDate = substr($mDate,0,4).'-'.substr($mDate,4,2).'- '.substr($mDate,6,2).' '.substr($mDate,8,2).':'.substr($mDate,10,2).':'.substr($mDate,12,2); break; This is the biggest problem I am facing at the moment and when I print the different lines, it indicates the correct IMEI but it does not loop through the whole file to use each string that belongs to that IMEI. Your assistance would be greatly appreciated. Thank you so much. Example of input file: Rx:00:00:00 28/02/2018:+RESP:GTFRI,3C0103,862045030241360,,14067,11,1,1,29.7,320,151.1,30.949307,-29.819685,20180227235959,0655,0001,013A,87B6,00,35484.1,01500:51:31,,,100,220101,,,,20180228000000,3461$ Rx:00:00:01 28/02/2018:+RESP:GTERI,380201,869606020047340,gv65,00000002,14076,10,1,1,119.0,119,24.3,18.668516,-34.016808,20180227235955,0655,0001,00F7,2DC9,00,98912.0,02235:20:25,0,100,220101,0,0,20180227235958,FF20$ Rx:00:00:03 28/02/2018:+RESP:GTERI,380201,869606020162990,,00000002,12912,10,1,1,0.0,230,1127.3,30.846671,-27.674206,20180227235956,0655,0001,013E,88B0,00,106651.1,03546:44:42,0,100,210101,0,0,20180227235959,6190$ Rx:00:00:03 28/02/2018:+ACK:GTHBD,450102,865084030005340,gb100,20180228000003,CC61$ Rx:00:00:03 28/02/2018:+RESP:GTERI,380201,869606020115980,,00000002,13640,10,1,1,12.1,353,1663.1,28.580726,-28.162208,20180227235957,,,,,,37599.6,02422:07:24,0,100,220101,0,0,20180228000000,1937$ Rx:00:00:04 28/02/2018:+RESP:GTERI,380502,869606020276840,gv65,00000002,12723,10,1,1,0.0,106,1232.8,22.878013,-27.951762,20180227235952,0655,0001,0204,63C5,00,13808.9,00778:32:20,0,100,210100,0,0,20180228000002,2C50$ Rx:00:00:04 28/02/2018:+RESP:GTERI,380502,869606020274530,gv65,00000002,12683,10,1,1,0.0,91,1213.7,24.863444,-28.174319,20180227235956,0655,0001,0203,69F1,00,9753.2,00673:49:21,0,100,210100,0,0,20180228000003,8AC7$ Rx:00:00:05 28/02/2018:+ACK:GTHBD,380201,863286023083810,,20180228000003,0D87$ Rx:00:00:06 28/02/2018:+RESP:GTFRI,3C0103,862045030241360,,14086,10,1,1,34.0,327,152.0,30.949152,-29.819501,20180228000002,0655,0001,013A,87B6,00,35484.1,01500:51:36,,,100,220101,,,,20180228000005,3462$ Rx:00:00:06 28/02/2018:+ACK:GTHBD,060228,862894021626380,,20180228000007,F9A5$ Rx:00:00:07 28/02/2018:+RESP:GTERI,380201,869606020019430,,00000002,12653,10,1,1,0.0,219,1338.7,26.882063,-28.138099,20180228000002,,,,,,86473.7,05645:48:34,0,93,210101,0,0,20180228000003,0FA5$ Rx:00:00:09 28/02/2018:+ACK:GTHBD,380502,869606020233940,gv65,20180228000008,7416$ Rx:00:00:10 28/02/2018:+RESP:GTAIS,380201,869606020171710,,11,11,1,1,0.0,95,281.2,30.855164,-29.896575,20180228000009,0655,0001,0156,9A9F,00,156073.7,20180228000008,F9A4$ Each GT message means something which is why i need to extract only one specific IMEI and use the result in my function as a breakdown of what every set of numbers between the commas actually mean. The end result needs to be populated in an excel spreadsheet but that's a different issue.
Nested foreach, keeping tracking of the IMEIs you've already gone through. Or something like this. <?php $filename = 'info.txt'; $contents = file($filename); foreach ($contents as $line) { $doneAlreadyArray = array(); $IMEI = GetParam($line, 2); foreach ($contents as $IMEIline){ $thisIMEI = GetParam($IMEIline,2); //check if already done the IMEI previously if (!in_array($thisIMEI, $doneAlreadyArray)){ //matching IMEIs? if ($thisIMEI == $IMEI){ //run new function with entire $IMEIline new_function($IMEIline); } } } //add IMEI to doneAlreadyArray array_push($doneAlreadyArray,$IMEI); } ?>
If I've understood your question right and you want to extract the string(line) with the same Unique identifier, this may be useful for your needs as a strating point. The example is very basic, and use data from your question: <?php // Read the file. $filename = 'input.txt'; $file = file($filename, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES); // Each item of $output will contain an array of lines: $output = array(); foreach ($file as $row) { $a = explode(',', $row); $imei = $a[2]; if (!array_key_exists($imei, $output)) { $output[$imei] = array(); } $output[$imei][] = $row; } // Then do what you want ... foreach ($output as $key=>$value) { echo 'IMEI: '.$key.'</br>'; foreach($value as $row) { // Here you can call your functions. I just echo the row: echo $row.'</br>'; } } ?>
thank you for the feedback. Ryan Dewberry ended up helping me. The fix was simpler than I thought too :) //Unknownfunction is now $line function GetParam($line, $numberCommas) { $returnString = ""; $foundSting = 0; $numberFound = 0; $len = strlen($line); for ($i = 0; $i < $len; ++$i) { if ($line[$i] == ",") { ++$numberFound; if ($numberFound > $numberCommas) break; if ($numberFound == $numberCommas) $foundSting = 1; } else if ($foundSting == 1) { $returnString .= $line[$i]; } } return $returnString; // print $returnString; } //this is new - makes sure I use the correct IMEI $contents = file($fileName); foreach ($contents as $line){ $haveData = 0; $IMEI = GetParam($line, 2); if ($IMEI == $gprsid){ $i = strpos($line, ":GT"); $p = substr($line, $i+3,3); $Protocol = GetParam($line, 1); //this is the part I struggled with as well - This is an array of all of my //calculation //results and in printing it out I can see that everything is working $superResult = array(); array_push($superResult,$result2); print_r($superResult); } } Much appreciated. Thank you!
Find Word Which comes first in php
I have 2 words like %sku% and %any% that will be used in the sites url structure. This data will be saved in a database and I need to find out which comes first. E.g. In the below url %sku% comes first http://example.com/%sku%/product/%any% While in the below url %any% comes first http://example.com/%any%/product/%sku% Furthermore I cant be sure that the structure will be consistent it could be like any of the below: http://example.com/%sku%/product/%any% http://example.com/%any%/product/%sku% http://example.com/%any%/%sku% http://example.com/product/%sku% http://example.com/product/%any% I want to check which comes first and which comes last.. but %sku% and%any%` are defined by me.. so i can be 100% sure that those tags are going to be used.
The following code will return the first and last occurring items from a designated $attributes array. $string = 'http://example.com/%sku%/product/%any%'; // values to check for $attributes = ['%sku%', '%any%']; $results = array(); foreach($attributes as $attribute) { // Get position of attribute in uri string $pos = strpos($string, $attribute); // if it exists we add it to the array with the position if($pos) { $results[$attribute] = $pos; } } // Get the first occuring attribute $firstOccuringAttribute = array_search( min($results), $results); // Get the last occuring attribute $lastOccuringAttribute = array_search( max($results), $results); This could be refactored into something a bit more readable: $uri = 'http://example.com/%sku%/product/%any%'; $attributes = ['%sku%', '%any%']; $lastAttribute = getLastAttribute($uri, $attributes); $firstAttribute = getFirstAttribtue($uri, $attributes); function getAttributeWeighting($uri, $attributes) { $results = array(); foreach($attributes as $attribute) { $pos = strpos($uri, $attribute); if($pos) { $results[$attribute] = $pos; } } return $results; } function getFirstAttribute($uri, $attributes) { $attributeWeighting = getAttributeWeighting($uri, $attributes); return array_search( min($attributeWeighting), $attributeWeighting); } function getLastAttribute($uri, $attributes) { $attributeWeighting = getAttributeWeighting($uri, $attributes); return array_search( max($attributeWeighting), $attributeWeighting); }
Just use strpos something like: $URL = "http://$_SERVER[HTTP_HOST]$_SERVER[REQUEST_URI]"; $posOfSku=strlen($URL); $posOfAny=strlen($URL); if(strpos($URL ,'%sku%') !== false) { $posOfSku = strpos($URL ,'%sku%'); } if(strpos($URL ,'%any%') !== false) { $posOfAny= strpos($URL ,'%any%'); } $result = ($posOfAny < $posOfSku) ? 'any came 1st' : 'sku came 1st'; echo $result;
Using nested foreach loop on same array
Is it ok to loop array again in nested loop and also change the array? I've an URL's array with entries(as array key) of either an URL or domain:example.com In case of this entry : domain:example.com I want to remove all URLS containing example.com as domain: foreach (array_keys($urls1) as $line) { if (preg_match('/domain:(.*)/i', $line, $matches)) { $domain = $matches[1]; foreach (array_keys($urls1) as $line2) { if ($url_domains[$line2] == $domain) { unset($urls1[$line2]); } } } }
There is no problem looping over it a second time, however you will get yourself and your code into a big knot if you start removing items. My suggestion would be to save a copy and modify that. This is not ideal, but I'm not sure what you wish to do. //Make a copy of your array $URLCopy = $urls1; foreach (array_keys($urls1) as $line) { if (preg_match('/domain:(.*)/i', $line, $matches)) { $domain = $matches[1]; foreach (array_keys($urls1) as $line2) { if ($url_domains[$line2] == $domain) { unset($URLCopy[$line2]); } } } }
I ran into a similar problem and making a copy of the array was the answer. This was my problem: If a particular text string existed towards the beginning of the file and (an array of approximately 80 members) matched a string towards the end of the file, I had to remove three lines towards the end. The problem that happened when I didn't use a copy is that the index would reset from 30, back to 9, and this caused me some issues. This is what worked for me. $rowCopy = $row foreach($row as $index => &$line) { ////previous code if ($line[0] === "NM1" && $line[1] === "77") { //read through the $row array and find the NM*85 string foreach ($rowCopy as $index2 => $lineT) { if ($s = strpos($lineT, "NM1*85") !== false) { $npiTest = explode("*", $lineT); if (strcmp(preg_replace("/[^0-9,.]/", "", $npiTest[9]), $line[9]) === 0) { // $line = false; $index--; unset($row[$index + 1]); $index++; unset($row[$index + 1]); $index++; unset($row[$index + 1]); $erased = $erased + 3; $index++ } } } } }
Data Not Being Parsed Correctly
I have a simple data format that goes as follows: stuff/stuff/stuff An example would be: data/test/hello/hello2 In order to retrieve a certain piece of data, one would use my parser, which tries to do the following: In data/test/hello/hello2 You want to retrieve the data under data/test (which is hello). My parser's code is below: function getData($data, $pattern) { $info = false; $dataLineArray = explode("\n", $data); foreach($dataLineArray as &$line) { if (strpos($line,$pattern) !== false) { $lineArray = explode("/", $line); $patternArray = explode("/", $pattern); $iteration = 0; foreach($lineArray as &$lineData) { if($patternArray[$iteration] == $lineData) { $iteration++; } else { $info = $lineData; } } } } return $info; } However, it always seems to return the last item, which in this case is hello2: echo getData("data/test/hello/hello2", "data/test"); Gives Me; hello2 What am I doing wrong?
If you want the first element after the pattern, put break in the loop: foreach($lineArray as $lineData) { if($patternArray[$iteration] == $lineData) { $iteration++; } elseif ($iteration == count($patternArray)) { $info = $lineData; break; } } I also check $iteration == count($patternArray) so that it won't return intermediate elements, e.g. /data/foo/test/hello/hello2 will return hello rather than foo. P.S. There doesn't seem to be any reason to use references instead of ordinary variables in your loops, since you never assign to the reference variables.