Is it possible to combine strtok() and substr()? - php

I've recently started working with PHP and am trying to make a list from a .txt BUT removing all the unnecessary components.
a line got this
item = 0 egg came_from_chicken
I want to remove the item = and the came_from_chicken which leaves me with 0 egg.
Now after some searching I've found substr() to remove the first 5 characters of each of my lines. Later I've also found that strtok() can remove the rest of the unwanted text after the second tab. Unfortunately I cannot combine these. So my question is: How to remove the first 5 chars from each line and remove everything after the second tab from each line?
I've got this so far:
<?php
$lines = file('../doc/itemlist.txt');
$newf = array();
foreach ($lines as $line) {
$newf[] = strtok($line, "\t") . "\t" . strtok("\t");
}
var_dump($newf);
?>
This works like a charm to remove everything after egg but still have to remove item =.

The quick-and-dirty way is to just wrap it all:
$newf[] = substr(strtok($line, "\t") . "\t" . strtok("\t"), 5);
But, I personally have a dislike for strtok() (can't explain why, I just don't like it). If you don't need to strip everything off from the second tab, but from the last tab (in your example the second tab is the last tab), I would use strrpos() to find the location of the last tab, and dump that into substr():
$newf[] = substr($line, 5, strrpos($line, "\t")-5);
That -5 is to compensate for the 5 characters you strip off from the beginning. If you need to start at character 6 instead of 5, you should also subtract 6 from whatever strrpos() returns.
Edit Never mind that whole last part, I just saw the example format you posted and you really need the second tab instead of the last tab.

You can use a regular expression:
<?php
$lines = file('./file.txt');
$newf = array();
foreach ($lines as $line) {
$newf[] = preg_replace('/.*=\s*(.*)\t.*/s', '$1', $line);
}
var_dump($newf);
Output:
array(1) {
[0]=>
string(5) "0 egg"
}

Assuming that you will be receiving similar patterns to the example you gave.
You can just do a simple line of:
$str = "item = 0 egg came_from_chicken";
$parts = preg_split('/\s+/', $str);
echo $parts[2] . $parts[3];

I know this is not the answer you are looking for using strtok but I believe it would be much easier to do the following code below:
<?php
$lines = '../doc/itemlist.txt';
// array to store all data
$newf = array();
foreach ($lines as $line) {
// you can do an explode which will turn it into an array and you can then get any values you want
// $newf [] = strtok ($line, "\t") . "\t" . strtok("\t"); // throw away
// lets say we use [item = 0 egg came_from_chicken] as our string
// we split it into an array for every tab or spaces found
$values = preg_split ('/\s+/', $line);
//returns
// Array
// (
// [0] => item
// [1] => =
// [2] => 0
// [3] => egg
// [4] => came_from_chicken
// [5] =>
// )
// lastly store your values which would be sub 2 and sub 4
$newf [] = $values [2] . ' ' . $values [3];
}
var_dump($newf);
// return
// array (size=3)
// 0 => string '0 aaa' (length=5)
// 1 => string '1 bbb' (length=5)
// 2 => string '2 ccc' (length=5)
?>

This approach will work with any string preceeding the = symbol.
foreach ($lines as $line) {
$newf[] = implode("\t", array_slice(explode("\t", trim(explode('=', $line, 2)[1])), 0, 2));
}

Related

Shortcode style parsing

Looking at how WP uses shortcodes I thoufght I could implement the same structure into a project, I assumed this would be availble somwehere but have yet to track down.
I started to parse myself starting with a preg_match_all
preg_match_all('/[[^]]*]/', $content, $match);
and that return the array with all the shortcodes inside content as expected but then looking at parsing the name, variables or array keys with values I start getting real heavy on parsing.
My current thought is to break up on spaces, then parse each but then i run into spaces in the values even though they are in quotes. So if i parse quoted data first then spaces to re-construct it seems very wasteful. I don't need to re-invent the wheel here so any input is fantastic.
example
[shortcodename key1="this is a value" key2="34"]
would like to have
Array
(
[shortcodename] => Array
(
[key1] => this is a value
[key2] => 34
)
)
here is the complete function that is working if anyone else is looking to do the same, obviously this is not meant to run user content but the called function should do any checks as this only replaces the shortcode if the funtction has a return value.
function processShortCodes($content){ // locate data inside [ ] and
//process the output, place back into content and returns
preg_match_all('/\[[^\]]*\]/', $content, $match);
$regex = '~"[^"]*"(*SKIP)(*F)|\s+~';
foreach ($match[0] as $key => $val){
$valOrig = $val; // keep uncleaned value to replace later
$val = trim(substr($val, 1, -1));
$replaced = preg_replace($regex,":",$val);
$exploded = explode(':',$replaced);
if (is_array($exploded)){
$fcall = array();
$fcallName = array_shift($exploded); // function name
if (function_exists($fcallName)){ // If function exsist then go
foreach ($exploded as $aKey => $aVal){
$arr = explode("=", $aVal);
if (substr($arr[1], 0, 1) == '&'){
$fCall[$arr[0]]=substr($arr[1], 6, -6); // quotes can be "
}else{
$fCall[$arr[0]]=substr($arr[1], 1, -1);
}
}
if ( is_array($fCall) && $fcallName ){
$replace = call_user_func($fcallName, $fCall);
if ($replace){
$content = str_replace($valOrig,$replace,$content);
}
}
}
}
}
You can try this to change all spaces not wrapped in quotes to let's say a semicolon then explode by semicolon
$regex = '~"[^"]*"(*SKIP)(*F)|\s+~';
$subject = 'hola hola "pepsi cola" yay';
$replaced = preg_replace($regex,";",$subject);
$exploded = explode(';', $replaced);
Credits

php explode by comma ignore thousands seperator

I am scraping the following kind of strings from an external resource which I can't change:
["one item",0,0,2,0,1,"800.12"],
["another item",1,3,2,5,1,"1,713.59"],
(etc...)
I use the following code to explode the elements into an array.
<?php
$id = 0;
foreach($lines AS $line) {
$id = 0;
// remove brackets and line end comma's
$found_data[] = str_replace(array('],', '[',']', '"'), array('','','',''), $line);
// add data to array
$results[$id] = explode(',', $line);
}
Which works fine for the first line, but as the second line uses a comma for the thousands seperator of the last item, it fails there. So somehow I need to disable the explode to replace stuff between " characters.
If all values would be surrounded by " characters, I could just use something like
explode('","', $line);
However, unfortunately that's not the case here: some values are surrounded by ", some aren't (not always the same values are). So I'm a bit lost in how I should proceed. Anyone who can point me in the right direction?
You can use json_decode here since your input string appears to be a valid json string.
$str = '["another item",1,3,2,5,1,"1,713.59"]'
$arr = json_decode($str);
You can then access individual indices from resulting array or print the whole array using:
print_r($arr);
Output:
Array
(
[0] => another item
[1] => 1
[2] => 3
[3] => 2
[4] => 5
[5] => 1
[6] => 1,713.59
)

Read file and fetch particular lines how to [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 7 years ago.
Improve this question
people
I have a problem I want to read from a file and use and fetch some parts of the file like below. This is whats inside the file but I want to fetch the names. This file is used by my server and if a player logs in the server then the list of names get bigger. But I have no clue how to do it.. and I really want to know how to do so.
I already tryed stuff myself by exploding the first characters but thats how far my knowledge reaches.
Already Big thanks for the one so kind to help me out.
Players online: NAME1, NAME2, NAME3, NAME4, NAME5, NAME6, ETC, ETC. Total: 4
You can try this out :
$line = 'layers online: NAME1, NAME2, NAME3, NAME4, NAME5, NAME6, ETC, ETC. Total: 4';
$pattern = '/:(.*)[,.]/';
preg_match($pattern, $line, $matches);
$names = explode(',', $matches[1]);
print_r($names);
You could search for the first occurance of the : character and the position of Total: using strpos() and then use substr() to remove these unneeded parts from the string. You could then split the string on each , character to get an array of names. Notice that the names will contain spaces so we could use array_walk() in conjunction with trim() to remove these:
// get the contents of your file
$data = file_get_contents('file.txt');
// get position of first ':' character
$pos1 = strpos($data, ':');
// get position of 'Total:'
$pos2 = strrpos($data, 'Total:');
// remove these parts using `substr()`
$data = substr($data, $pos1+1, ($pos2 - 1) - $pos1);
// split the string on each ',' character
$array = explode(",", $data);
// remove any whitespaces from the start and end
array_walk($array, function(&$value, $key) {
$value = trim($value);
});
// array now contains
Array
(
[0] => Admin Wouter
[1] => Krachtpatser
[2] => Dark Warrior
[3] => Anneleen.
)
To make sure you don't have any trailing '.' after a name you could modify the array_walk() callback like this:
array_walk($array, function(&$value, $key) {
// trim whitespaces
$value = trim($value);
// trim trailing '.' characters
$value = rtrim($value, '.');
});
$s = 'Players online: Admin Wouter, Krachtpatser, Dark Warrior, Anneleen. Total: 4';
// or read from the players file:
//$s = file_get_contents('path_to_players_file');
$s = str_replace('Players online: ', '', $s);
$stringPlayers = substr($s, 0, strrpos($s, '. Total:'));
echo $stringPlayers; // displays: Admin Wouter, Krachtpatser, Dark Warrior, Anneleen
// now get the player names in an array:
$arrayPlayers = explode(',', $stringPlayers);
foreach ($arrayPlayers as $k => $name) {
$arrayPlayers[$k] = trim($name);
}
echo '<pre>';
print_r($arrayPlayers);
echo '</pre>';
/* Displays:
Array
(
[0] => Admin Wouter
[1] => Krachtpatser
[2] => Dark Warrior
[3] => Anneleen
)
*/

Add delimiter in string coming from url in PHP

Merchant Id|Merchant|Website|Transaction In Period|Voids In Period|Gross Sales Amount|Total Commision in Period
9766|Mountains Plus Outdoor Gear|www.MPGear.com|1|0|88.91|8.89
12447|Meritline.com|www.meritline.com|5|0|52.86|3.71
16213|East Coast Fashions|www.discountstripper.com|1|0|32.27|3.23
17226|HRM USA|www.HeartRateMonitorsUSA.com|1|0|189.9|6.65
I am getting above string from url now now I want convert that string to array based on split delimiter |
But there is a problem after end of each new row there is not placed delimiter | so I want that to placed that delimiter after each row end.
Note :: all columns will be predefined and it will return same all time request.
I am using this code to convert that string to array . This code is working perfect if there will be all delimiter placed correctly in string.
$NumColumns = 6;
$Delim = "|";
$data = array_chunk(explode($Delim,$contents), $NumColumns);
output will be like this
Array
(
[0] => Array
(
[0] => Merchant Id
[1] => Merchant
[2] => Website
[3] => Transaction In Period
[4] => Voids In Period
[5] => Gross Sales Amount
[6] => Total Commision in Period
)
[1] => Array
(
[0] => 9766
[1] => Mountains Plus Outdoor Gear
[2] => www.MPGear.com
[3] => 1
[4] => 0
[5] => 88.91
[6] => 8.89
)
-----
----
)
Try using str_getcsv or explode.
<?php
$data_from_url = "Merchant Id|Merchant|Website|Transaction In Period|Voids In Period|Gross Sales Amount|Total Commision in Period
9766|Mountains Plus Outdoor Gear|www.MPGear.com|1|0|88.91|8.89
12447|Meritline.com|www.meritline.com|5|0|52.86|3.71
16213|East Coast Fashions|www.discountstripper.com|1|0|32.27|3.23
17226|HRM USA|www.HeartRateMonitorsUSA.com|1|0|189.9|6.65";
$splitted_data = explode(PHP_EOL, $data_from_url);
/**
* print_r($splitted_data) will be
* Array
* (
[0] => "Merchant Id|Merchant|Website|Transaction In Period|Voids In Period|Gross Sales Amount|Total Commision in Period"
[1] => "9766|Mountains Plus Outdoor Gear|www.MPGear.com|1|0|88.91|8.89"
...
* )
*/
// You can now iterate through the lines
$output1 = array();
foreach($splitted_data as $row) {
$output1[] = str_getcsv(trim($row), '|'); // parses a
// OR
//$output1[] = explode('|', trim($row));
}
// OR use array_map with callback function
$output2 = array_map(function($line){ return explode('|', trim($line)); }, $splitted_data);
$output3 = array_map(function($line){ return str_getcsv(trim($line), '|'); }, $splitted_data);
var_dump($output1, $output2, $output3); // The result you want to achive
?>
I would do this as a 2-step process. First split it into lines on the \n (newline) character, and then split each line on the | character.
You can do that in only a couple lines, like this:
$lines = explode("\n", $contents);
$data = array_map(function($line) {return explode('|', trim($line));}, $lines);
You can see this working here: http://phpfiddle.org/main/code/9fv-h2c
Once I split the contents into individual lines, I'm using the array_map() function to apply the same operation to every element of the array (every line).
array_map() calls a callback function (which I define as an anonymous function) for each element in the array. In this instance, I've defined a simple function that trims the line to remove any extra spaces there may be, and then splits it on the | character to get the individual fields.
If the array_map line is a bit complicated, I could illustrate how it's working by rewriting it without the anonymous function like this:
function processLine($line) {
$line = trim($line);
$fields = explode('|', $line);
return $fields;
}
$data = array_map('processLine', $lines);
...or even rewriting it without using array_map like this:
function processLine($line) {
$line = trim($line);
$fields = explode('|', $line);
return $fields;
}
$data = array();
foreach ($lines as $l) {
$data[] = processLine($l);
}
If I understand your question correctly, you're trying to split the data, but want to keep the delimiter | as part of the string.
Using preg_split, you can do this like so:
$arr = preg_split('/([^|]*\|)/', $string, PREG_SPLIT_NO_EMPTY | PREG_SPLIT_DELIM_CAPTURE);
The expression matches zero or more chars that aren't | ([^|]*)
and matches the delimiting |. the combination of the two is used as delimiter. In other words, everything is a delimiter now.
That's why we have to use the predefined constant PREG_SPLIT_DELIM_CAPUTRE.
Of course, between the delimiters, there's nothing, but preg_split will capture this nothing-ness, too and add empty matches in the resulting array. That's why we have to use the other predefined constant: PREG_SPLIT_NO_EMPTY.
The two constants are combined by means of the bitwise OR operator |
$output = explode(PHP_EOL, $input);
foreach($output as &$line)
{//$line is a reference here, important!
$line = preg_split('/([^|]*\|)/', $line, PREG_SPLIT_NO_EMPTY | PREG_SPLIT_DELIM_CAPTURE);
}
This should produce the desired ouptut, assuming you want the delimiting | kept in the strings. if not:
$output = explode(PHP_EOL, $input);
foreach($output as &$line)
{
$line = explode('|', $line);
}
That's it, really...

Separate each word into a Array

I have a file with contents like :
Apple 100
banana 200
Cat 300
I want to search for a particular string in the file and get the next word. Eg: I search for cat, I get 300. I have looked up this solution: How to Find Next String After the Needle Using Strpos(), but that didn't help and I didn't get the expected output. I would be glad if you can suggest any method without using regex.
I'm not sure this is the best approach, but with the data you've provided, it'll work.
Get the contents of the file with fopen()
Separate the values into array elements with explode()
Iterate over your array and check each element's index as odd or even. Copy to new array.
Not perfect, but on the right track.
<?php
$filename = 'data.txt'; // Let's assume this is the file you mentioned
$handle = fopen($filename, 'r');
$contents = fread($handle, filesize($filename));
$clean = trim(preg_replace('/\s+/', ' ', $contents));
$flat_elems = explode(' ', $clean);
$ii = count($flat_elems);
for ($i = 0; $i < $ii; $i++) {
if ($i%2<1) $multi[$flat_elems[$i]] = $flat_elems[$i+1];
}
print_r($multi);
This outputs a multidimensional array like this:
Array
(
[Apple] => 100
[banana] => 200
[Cat] => 300
)
Try this, it doesn't use regex, but it will be inefficient if the string you're searching is longer:
function get_next_word($string, $preceding_word)
{
// Turns the string into an array by splitting on spaces
$words_as_array = explode(' ', $string);
// Search the array of words for the word before the word we want to return
if (($position = array_search($preceding_word, $words_as_array)) !== FALSE)
return $words_as_array[$position + 1]; // Returns the next word
else
return false; // Could not find word
}
$find = 'Apple';
preg_match_all('/' . $find . '\s(\d+)/', $content, $matches);
print_r($matches);
You might benefit from using named regex subpatterns to capture the information you're looking for.
For example you, finding a number the word that is its former (1 <= value <= 9999)
/*String to search*/
$str = "cat 300";
/*String to find*/
$find = "cat";
/*Search for value*/
preg_match("/^$find+\s*+(?P<value>[0-9]{1,4})$/", $str, $r);
/*Print results*/
print_r($r);
In cases where a match is found the results array will contain the number you're looking for indexed as 'value'.
This approach can be combined with
file_get_contents($file);

Categories