I have a text file containing data/fields which are separated by exact column no. Each new line represents a new row of data.
Example of file content:
John Chow 26 543 Avenue Street
From the above, first 10 columns are for the name. Next two are for age. And the rest are for the address.
I need to segregate those data from the uploaded file and display it to the user in a formatted table, which will later on be inserted into the database upon confirmation by user.
I am new to PHP. I think substr could work.
Please guide me on how to go about it. I am using codeigniter with PHP, but basic steps in plain PHP will do. Thanks
Read every line of the file, and parse the lines with either substr or regular expression:
$data = array();
$h = fopen($uploadedfile,"r");
while (false !== ($line = fgets($h)))
{
/* substring way: */
$data[] = array(
'name' => trim(substr($line,0,10)),
'age' => intval(sbstr($line,10,2),10),
'address' => trim(substr($line,12))
);
/* regular expression way: */
preg_match("'^(.{10})(.{2})(.*)$'",$line,$n);
$data[] = array(
'name' => trim($n[1]),
'age' => intval($n[2],10),
'address' => trim($n3)
);
}
fclose($h);
Then iterate the $data array to display it in a table form.
Edit: what you ask in the comments can be done also with regular expressions. If $val is the parsed 10 character string, then:
$val = preg_replace("'^0*'","",$val);
would replace all leading 0s.
Yes, you should be using substr. This extracts part of the string. Something like:
$name = trim(substr($line, 0, 10));
$age = trim(substr($line, 10, 2));
$addr = trim(substr($line, 12));
I've added trim to remove any extra whitespace.
Umm I suggest you don't use substr, because peoples names are not always going to be the same length so this will create some problems. I think the explode and implode functions would do the trick better for you, they split a string into an array and back.
http://php.net/manual/en/function.explode.php
http://www.php.net/manual/en/function.implode.php
<?PHP
$str = "John Chow 26 543 Avenue Street";
$data = explode(" ", $str);
$first_name = $data[0];
$last_name = $data[1];
$age = $data[2];
$address = implode(" ", array_slice($data, 3));
?>
You can use a regexp:
if (preg_match('/(.{10})(.{2})(.{12})/', $input, $output)) {
var_dump($output);
}
Related
I apologize for a confusing title. Basically, i'm facing a problem with my website which ends up bugging it completely. I need to basically remove all duplicate entries on the same line, on all lines in my text file list. I.e.
123123
123
123
Sometimes i get entries like 123123 on the same line when it should just be 123, on each line. This is just an example of course, it's hard for me to explain. I apologize again. I hope this was enough for you to gasp what i mean.
To sum it up, i'm need to remove the duplicate part of the string 123123, so it's just 123, for all of the lines in my text file.
Help appreciated.
A live example for this:
2017-06-21:127.0.0.12017-06-21:127.0.0.1
2017-06-21:127.0.0.12017-06-21:127.0.0.1
2017-06-21:127.0.0.12017-06-21:127.0.0.1
2017-06-21:127.0.0.1
$linesStr = '2017-06-21:127.0.0.12017-06-21:127.0.0.1
2017-06-21:127.0.0.12017-06-21:127.0.0.1
2017-06-21:127.0.0.12017-06-21:127.0.0.1
2017-06-21:127.0.0.1';
//can be \n only
$lines = explode("\r\n", $linesStr);
//loop through all lines
foreach($lines as $i => $line)
{
$lineLen = ceil(strlen($line) / 2);
$first = substr($line, 0, $lineLen);
$second = substr($line, $lineLen);
if($first == $second)
{
$lines[$i] = $first;
}
}
$lines = implode("\r\n", $lines);
This should do it...
A basic algorithm to deduplicate a string:
Split it in half.
If the both halves are the same, replace the whole string with either half.
Caveat: this doesn't care whether or not the string was intended to be a duplicate or not, and consequently may remove some things you don't want it to.
function deduplicate($str) {
$str = trim($str);
list($beginning, $end) = str_split($str, strlen($str) / 2);
return ($beginning == $end) ? $end : $str;
}
Assuming you have an array of lines from your file you can apply it with array_map.
$lines = array_map('deduplicate', $lines);
I want to split a string such as the following (by a divider like '~##' (and only that)):
to=enquiry#test.com~##subject=test~##text=this is body/text~##date=date
into an array containing e.g.:
to => enquiry#test.com
subject => test
text => this is body/text
date => date
I'm using php5 and I've got the following regex, which almost works, but there are a couple of errors and there must be a way to do it in one go:
//Split the string in the url of $text at every ~##
$regexp = "/(?:|(?<=~##))(.*?=.*?)(?:~##|$|\/(?!.*~##))/";
preg_match_all($regexp, $text, $a);
//$a[1] is an array containing var1=content1 var2=content2 etc;
//Now create an array in the form [var1] = content, [var2] = content2
foreach($a[1] as $key => $value) {
//Get the two groups either side of the equals sign
$regexp = "/([^\/~##,= ]+)=([^~##,= ]+)/";
preg_match_all($regexp, $value, $r);
//Assign to array key = value
$val[$r[1][0]] = $r[2][0]; //e.g. $val['subject'] = 'hi'
}
print_r($val);
My queries are that:
It doesn't seem to capture more than 3 different sets of parameters
It is breaking on the # symbol and so not capturing email addresses e.g. returning:
to => enquiry
subject => test
text => this is body/text
I am doing multiple different regex searches where I suspect I would be able to do one.
Any help would be really appreciated.
Thanks
Why are you using regex when there is much simple method to do this by explode like this
$str = 'to=enquiry#test.com~##subject=test~##text=this is body/text~##date=date';
$array = explode('~##',$str);
$finalArr = array();
foreach($array as $val)
{
$tmp = explode('=',$val);
$finalArr[$tmp['0']] = $tmp['1'];
}
echo '<pre>';
print_r($finalArr);
How do I modify the last element in an array?
The array looks like this:
$fields = array("firstName = 'Bob', ",
"lastName = 'Smith', ",
"email = 'bob#example.com', ",
"address = '123 anystreet', ");
The array is generated by a script which creates the values and adds the comma/space at the end of each string. I want to remove that comma/space from only the last element in that array. Keep in mind that the values could in fact contain a comma/space combination so only the last element and the last two characters of the last element need to be removed.
I've looked at the end() function but I don't think that is going to help since it just gets the value.
Edit Ok so I created this function/array so that I would only have one mysql function to update users. Sort of like a detect changes function and it only passes back the required/changed fields. I didn't realize there were problems associated with this approach. I thought that since I already had the mysql queries written in my old functions there shouldn't be an issue with this way. The file that it's in will not be accessible to the public. I'm going to use the best answer that works for me but I'm going to search for why this is problematic and I would appreciate comments/links as to what is wrong with this approach.
Like this!
end($array);
$key = key($array);
reset($array);
There's a shorthand way to do this, but it's easier to follow if it's broken out into pieces:
$index = count( $fields ) - 1;
$value = $fields[$index];
$fields[$index] = preg_replace( "/,\ $/", "", $value );
To change the value of the last numeric element:
$lastValue = array_pop($fields);
$fields[] = rtrim(', ',$lastValue);
If you are preparing these values for a query I would suggest storing everything without commas in an array then calling implode on that array when needed to prevent trailing comma problems
Array pop and push are the easiest way to do it for basic arrays. (I know that isn't technically the question but many people will come here looking for the answer in relation to simple arrays as well).
<?php
function update_last(&$array, $value){
array_pop($array);
array_push($array, $value);
}
?>
Then you can use the function like this:
<?php
$array = [1,2,3];
update_last($array, 4); //$array = [1,2,4];
?>
There are few ways:
1) For associative arrays, if you don't know the last element key, you better find the last element key first and change its value.
$array[end((array_keys($array)))] .= ' additional text';
2) if you don't know and don't care about keys, you can cut the last element and create a new one.
$array[] = array_pop($array).' additional text';
The last element of an array can always be retrieved using array_pop(), no matter how the array is indexed. It will also remove that element from the array, which is very useful if we want to modify and then add it again, as you cannot modify the element in-place.
What you are trying to do can be done with a simple, single line of code:
$fields[] = preg_replace("/, $/", "", array_pop($fields));
That's it. Here's what it does:
preg_replace() searches for a Regex pattern in a string and if found, replaces the match with an alternative string.
The pattern we search for is /, $/, which means: Match for ", " (comma + space) but only if it is at the very end of the string ($).
The replacement string is simply an empty string (""), thus the match is just deleted from the string.
The string we want to perform that replacement on is array_pop($fields), the last element of the array $fields, which is also removed from that array.
The modified string is then re-added to the array at the end ($fields[] = adds an element to an array without an explicit key and makes it the new last element).
Let's test it:
$fields = array(
"firstName = 'Bob', ",
"lastName = 'Smith', ",
"email = 'bob#example.com', ",
"address = '123 anystreet', ");
print "Before:\n\n";
print_r($fields);
$fields[] = preg_replace("/, $/", "", array_pop($fields));
print "\nAfter:\n\n";
print_r($fields);
Output:
Before:
Array
(
[0] => firstName = 'Bob',
[1] => lastName = 'Smith',
[2] => email = 'bob#example.com',
[3] => address = '123 anystreet',
)
After:
Array
(
[0] => firstName = 'Bob',
[1] => lastName = 'Smith',
[2] => email = 'bob#example.com',
[3] => address = '123 anystreet'
)
Note how the last comma is gone? Just try it yourself.
stumbled upon this today. i think the easiest non-pointer-breaking way would be:
array_splice($array, -1, 1, strtolower(end(array_values($array))).'blah' );
of course you can drop array_values if you dont have to care for the pointer.
but i wonder if this is a good way, since the extract-n-replace-stuff of splice could be more demanding than a pop or sth?
PHP 7 >= 7.3.0
$array[array_key_last($array)] = 'new value';
Demo
$fields = array(
"firstName = 'Bob', ",
"lastName = 'Smith', ",
"email = 'bob#example.com', ",
"address = '123 anystreet', "
);
$last = $fields[array_key_last($fields)];
$last = preg_replace( "/, $/", "", $last);
$fields[array_key_last($fields)] = $last;
I think PHP's Implode function might be a good alternative, instead of generating the commas yourself.
Barring that, you would have to use something like:
$lastfield = $fields[count($fields)-1];
$lastfield = str_split($lastfield,strlen($lastfield)-2);
$fields[count($fields)-1] = $lastfield;
The first and third lines are included to make the second line easier to read, but this could easily be compounded to one line.
id:10 Ivysaur Level:5
stored in side $_POST[A]
I'm trying just to grab the id (so the 10) and the name (which in this case is Ivysaur) and I want to store them in a session variable. But before I store them I'm trying to explode it so can split it into parts
$phoneChunks = explode("-", $_POST[A]);
echo "Raw Phone Number = $rawPhoneNumber <br />";
echo "First chunk = $phoneChunks[0]<br />";
echo "Second chunk = $phoneChunks[1]<br />";
echo "Third Chunk chunk = $phoneChunks[2]";
I am getting
Raw Phone Number =
First chunk = Id:10 Ivysaur Level:5
Second chunk =
Third Chunk chunk =
What am i doing wrong ???
preg_match("/id:(\d+) (.+?) Level:(\d+)/",$_POST['A'],$match);
list(,$id,$name,$level) = $match; // don't forget extra , at beginning of list!
Now you have the variables $id, $name and $level to do whatever you want with. Good luck from there :)
You are trying to explode on a dash when there is no dash in your string. Try this:
$phoneChunks = explode(" ", $_POST[A]);
Try this:
$chunk = explode(" ", $_POST['A']);
it should produce something like this:
Array
(
[0] => id:10
[1] => Ivysaur
[2] => Level:5
)
What am i doing wrong ???
You are not escaping $_POST['A']
$phoneChunks = explode(' ',hmtlentities($_POST['A']));
See: What are the best practices for avoiding xss attacks in a PHP site
I have a string
&168491968426|mobile|3|100|1&185601651932|mobile|3|120|1&114192088691|mobile|3|555|5&
and i have to delete, say, this part &185601651932|mobile|3|120|1& (starting with amp and ending with amp) knowing only the first number up to vertical line (185601651932)
so that in result i would have
&168491968426|mobile|3|100|1&114192088691|mobile|3|555|5&
How could i do that with PHP preg_replace function. The number of line (|) separated values would be always the same, but still, id like to have a flexible pattern, not depending on the number of lines in between the & sign.
Thanks.
P.S. Also, I would be greatful for a link to a good simply written resource relating regular expressions in php. There are plenty of them in google :) but maybe you happen to have a really great link
preg_replace("/&185601651932\\|[^&]+&/", ...)
Generalized,
$i = 185601651932;
preg_replace("/&$i\\|[^&]+&/", ...);
if you want real flexibility, use preg_replace_callback. http://php.net/manual/en/function.preg-replace-callback.php
Important: don't forget to escape your number using preg_quote():
$string = '&168491968426|mobile|3|100|1&185601651932|mobile|3|120|1&114192088691|mobile|3|555|5&';
$number = 185601651932;
if (preg_match('/&' . preg_quote($number, '/') . '.*?&/', $string, $matches)) {
// $matches[0] contains the captured string
}
It seems to me you ought to be using another data structure than a string to manipulate this data.
I'd want this data in a structure like
Array(
[id] => Array(
[field_1] => value_1
[field_2] => value_2
)
)
Your massive string can be massaged into such a structure by doing something like this:
$data_str = '168491968426|mobile|3|100|1&185601651932|mobile|3|120|1&114192088691|mobile|3|555|5&';
$remove_num = '185601651932';
/* Enter a descriptive name for each of the numbers here
- these will be field names in the data structure */
$field_names = array(
'number',
'phone_type',
'some_num1',
'some_num2',
'some_num3'
);
/* split the string into its parts, and place them into the $data array */
$data = array();
$tmp = explode('&', trim($data_str, '&'));
foreach($tmp as $record) {
$fields = explode('|', trim($record, '|'));
$data[$fields[0]] = array_combine($field_names, $fields);
}
echo "<h2>Data structure:</h2><pre>"; print_r($data); echo "</pre>\n";
/* Now to remove our number */
unset($data[$remove_num]);
echo "<h2>Data after removal:</h2><pre>"; print_r($data); echo "</pre>\n";