How to parse a mostly consistent filename into meaningful parts? - php

I have filenames like:
1234_56_78 A_FAIRLY_SHORT_TITLE_D.pdf
Luckily, the file naming is pretty consistent, but I can't absolutely guarantee that someone didn't use a space where they should have used an underscore.
With this in mind, I want to parse the string and extract the following details:
$project_no = '1234
$series_no = '56
$sheet_no = '78'
$revision = 'D'
$title = 'A Fairly Short Title'
Presently, I use the following to grab this info:
$filename = $_FILES['file']['name'][$i];
$filename = preg_replace('/\\.[^.\\s]{3,4}$/', '', $filename);
$parts = preg_split( "(_| )", $filename );
$project_no = $parts[0];
$series_no = $parts[1];
$sheet_no = $parts[2];
$revision = end($parts);
$title is simply everything that's left over after removing $parts[0] $parts[1], $parts[2], and end($parts), but how should I express that?
I thought I might be able to use
$title = implode(' ',\array_diff_key($parts, [0,1,2,end($parts)]));
But this doesn't remove the $revision bit at the end...
$title = FLOOR AS PROPOSED D
What am I missing, and am I unnecessarily over-complicating this?

The array_diff_key looks at key comparison of both arrays. end() just moves the internal pointer of the array and is actually useless since the value returned from it can't be used in computing difference between 2 arrays' keys.
Current comparison behaves as
array_diff_key([0,1,2,3,4,5,6,7], [0,1,2,'D'])
which looks key wise as:
array_diff_key([0,1,2,3,4,5,6,7], [0,1,2,3])
Hence, the end result of implode is concatenation of 4,5,6,7 keys' values.
To make the second parameter array values as keys, you can use array_flip to make keys as values and values as keys with the below expression:
$title = implode(' ',\array_diff_key($parts, array_flip([0,1,2,count($parts)-1])));
Demo: https://3v4l.org/J6b5r

I fear you are over-complicating this. I think a single preg_match() call is the most direct way to parse your string.
It looks like you grabbed the regex pattern from https://stackoverflow.com/a/2395905/2943403 to trim the extension from your filename; however, I recommend using a regex function when a single non-regex function serves the same purpose.
pathinfo($filename', PATHINFO_FILENAME)
Now that the extension has been removed, let's move on to the parsing.
Code: (Demo)
$filename = '1234_56_78 A_FAIRLY_SHORT_TITLE_D.pdf';
preg_match('~([^ _]+)[ _]([^ _]+)[ _]([^ _]+)[ _](.+)[ _](\S)~', pathinfo($filename, PATHINFO_FILENAME), $m);
var_export([
'project_no' => $m[1],
'series_no' => $m[2],
'sheet_no' => $m[3],
'title' => str_replace('_', ' ', $m[4]),
'revision' => $m[5],
]);
Output:
array (
'project_no' => '1234',
'series_no' => '56',
'sheet_no' => '78',
'title' => 'A FAIRLY SHORT TITLE',
'revision' => 'D',
)
If you are deadset on using preg_split(), then the pattern becomes super simple, but there is a little more mopping up to do.
Code: (Demo)
$filename = '1234_56_78 A_FAIRLY_SHORT_TITLE_D.pdf';
$m = preg_split('~ |_~', pathinfo($filename, PATHINFO_FILENAME));
$revision = array_pop($m);
var_export([
'project_no' => $m[0],
'series_no' => $m[1],
'sheet_no' => $m[2],
'title' => implode(' ', array_slice($m, 3)),
'revision' => $revision,
]);
// same output as earlier snippet

Related

Get matches from a preg_replace and use them as an array key

I want to get matches from a String and use them in a array as key to change the value in the string to the value of the array.
If it would be easier to realize, i can change the fantasy tags from %! also to whatever don't have problems in JS/jQuery. This script is for external JS Files and change some variables, which I can't Access from JS/jQuery. So I want to insert them with PHP and send them minified and compressed to the Browser.
$array = array ( 'abc' => 'Test', 'def' => 'Variable', 'ghi' => 'Change' );
$string ='This is just a %!abc!% String and i wanna %!ghi!% the %!def!%';
$string = preg_replace('%!(.*?)!%',$array[$1],$string);
echo $string;
You can use array_map with preg_quote to turn the keys of your array into regexes, and then use the values of the array as replacement strings in the array form of preg_replace:
$array = array ( 'abc' => 'Test', 'def' => 'Variable', 'ghi' => 'Change' );
$string ='This is just a %!abc!% String and i wanna %!ghi!% the %!def!%';
$regexes = array_map(function ($k) { return "/" . preg_quote("%!$k!%") . "/"; }, array_keys($array));
$string = preg_replace($regexes, $array, $string);
echo $string;
Output:
This is just a Test String and i wanna Change the Variable
Demo on 3v4l.org

PHP - preg_replace on an array not working as expected

I have a PHP array that looks like this..
Array
(
[0] => post: 746
[1] => post: 2
[2] => post: 84
)
I am trying to remove the post: from each item in the array and return one that looks like this...
Array
(
[0] => 746
[1] => 2
[2] => 84
)
I have attempted to use preg_replace like this...
$array = preg_replace('/^post: *([0-9]+)/', $array );
print_r($array);
But this is not working for me, how should I be doing this?
You've missed the second argument of preg_replace function, which is with what should replace the match, also your regex has small problem, here is the fixed version:
preg_replace('/^post:\s*([0-9]+)$/', '$1', $array );
Demo: https://3v4l.org/64fO6
You don't have a pattern for the replacement, or a empty string place holder.
mixed preg_replace ( mixed $pattern , mixed $replacement , mixed $subject)
Is what you are trying to do (there are other args, but they are optional).
$array = preg_replace('/post: /', '', $array );
Should do it.
<?php
$array=array("post: 746",
"post: 2",
"post: 84");
$array = preg_replace('/^post: /', '', $array );
print_r($array);
?>
Array
(
[0] => 746
[1] => 2
[2] => 84
)
You could do this without using a regex using array_map and substr to check the prefix and return the string without the prefix:
$items = [
"post: 674",
"post: 2",
"post: 84",
];
$result = array_map(function($x){
$prefix = "post: ";
if (substr($x, 0, strlen($prefix)) == $prefix) {
return substr($x, strlen($prefix));
}
return $x;
}, $items);
print_r($result);
Result:
Array
(
[0] => 674
[1] => 2
[2] => 84
)
There are many ways to do this that don't involve regular expressions, which are really not needed for breaking up a simple string like this.
For example:
<?php
$input = Array( 'post: 746', 'post: 2', 'post: 84');
$output = array_map(function ($n) {
$o = explode(': ', $n);
return (int)$o[1];
}, $input);
var_dump($output);
And here's another one that is probably even faster:
<?php
$input = Array( 'post: 746', 'post: 2', 'post: 84');
$output = array_map(function ($n) {
return (int)substr($n, strpos($n, ':')+1);
}, $input);
var_dump($output);
If you don't need integers in the output just remove the cast to int.
Or just use str_replace, which in many cases like this is a drop in replacement for preg_replace.
<?php
$input = Array( 'post: 746', 'post: 2', 'post: 84');
$output = str_replace('post: ', '', $input);
var_dump($output);
You can use array_map() to iterate the array then strip out any non-digital characters via filter_var() with FILTER_SANITIZE_NUMBER_INT or trim() with a "character mask" containing the six undesired characters.
You can also let preg_replace() do the iterating for you. Using preg_replace() offers the most brief syntax, but regular expressions are often slower than non-preg_ techniques and it may be overkill for your seemingly simple task.
Codes: (Demo)
$array = ["post: 746", "post: 2", "post: 84"];
// remove all non-integer characters
var_export(array_map(function($v){return filter_var($v, FILTER_SANITIZE_NUMBER_INT);}, $array));
// only necessary if you have elements with non-"post: " AND non-integer substrings
var_export(preg_replace('~^post: ~', '', $array));
// I shuffled the character mask to prove order doesn't matter
var_export(array_map(function($v){return trim($v, ': opst');}, $array));
Output: (from each technique is the same)
array (
0 => '746',
1 => '2',
2 => '84',
)
p.s. If anyone is going to entertain the idea of using explode() to create an array of each element then store the second element of the array as the new desired string (and I wouldn't go to such trouble) be sure to:
split on or : (colon, space) or even post: (post, colon, space) because splitting on : (colon only) forces you to tidy up the second element's leading space and
use explode()'s 3rd parameter (limit) and set it to 2 because logically, you don't need more than two elements

replace different sub strings in a string

I want to replace different sub-strings with multiple different strings in a string, is there a nicer way to do rather than i do labor work and use
str_replace ( mixed $search , mixed $replace , mixed $subject [, int &$count ] )
as many times as the number of strings to be replaced?
for example: replace a, b and c with d, e and f respectively in any sample string.
Of course i have a large number of words to change for this i need it.
str_replace() accepts an array for both search and replace parameters, so you can pass several strings in array to search and will be replaced by the corresponding strings in the array passed in replace parameter, like so:
$search = array('a','b','c');
$replace = array('d','e','f');
$res = str_replace($search, $replace, 'a b cool');
echo $res; //echoes 'd e fool'
The usual way of doing this is to supply an array of translations
$xlat = array(
'a' => 'd',
'b' => 'e',
'c' => 'f',
);
and then pass it to str_replace:
$result = str_replace(array_keys($xlat), array_values($xlat), $source);
You can build the array from a SQL query or other source.
You must be careful in case there is an intersection between the source and replacement string sets, or internal matches between source strings, e.g.
'Alpha' => 'Beta',
'Beta' => 'Gamma',
or even more sneaky,
'Alpha' => 'Beta',
'Alphabet' => 'ABCDEFGHIJ',
because internally str_replace employs a loop, and therefore "Base Alpha" would come out as "Base Gamma", and "Alphabet" as "Betabet" instead of "ABCDEFGHIJ". One possible way of coping with this is build $xlat incrementally; if you find that in the new couple 'a' => 'b', 'a' is already in the values of $xlat, you can push it onto $xlat instead of appending. Of course, more complicated sets of keywords (or even the exchange of two or more terms) might not be solvable.
Another way is to do it in two runs: you first generate a $xlat1 array of the form
'a' => '###<UNIQUEID1>###',
'b' => '###<UNIQUEID2>###',
and a second array of the form
'###<UNIQUEID1>###' => 'c',
'###<UNIQUEID2>###' => 'd',
You may "upgrade" the first one-array form to the second with a loop:
// First step, we sort $xlat in order of decreasing key size.
// This ensures that *Alphabet* will be replaced before *Alpha* is ever checked.
// Then we build
foreach($xlat as $from => $to)
{
$id = uniqid();
$xlat1[$from] = $id;
$xlat2[$id] = $to;
}
$temp = str_replace(array_keys($xlat1), array_values($xlat1), $source);
$result = str_replace(array_keys($xlat2), array_values($xlat2), $temp);

Convert flat array to a delimited string to be saved in the database

What is the best method for converting a PHP array into a string?
I have the variable $type which is an array of types.
$type = $_POST[type];
I want to store it as a single string in my database with each entry separated by | :
Sports|Festivals|Other
Use implode
implode("|",$type);
You can use json_encode()
<?php
$arr = array('a' => 1, 'b' => 2, 'c' => 3, 'd' => 4, 'e' => 5);
echo json_encode($arr);
?>
Later just use json_decode() to decode the string from your DB.
Anything else is useless, JSON keeps the array relationship intact for later usage!
json_encode($data) //converts an array to JSON string
json_decode($jsonString) //converts json string to php array
WHY JSON : You can use it with most of the programming languages, string created by serialize() function of php is readable in PHP only, and you will not like to store such things in your databases specially if database is shared among applications written in different programming languages
One of the Best way:
echo print_r($array, true);
No, you don't want to store it as a single string in your database like that.
You could use serialize() but this will make your data harder to search, harder to work with, and wastes space.
You could do some other encoding as well, but it's generally prone to the same problem.
The whole reason you have a DB is so you can accomplish work like this trivially. You don't need a table to store arrays, you need a table that you can represent as an array.
Example:
id | word
1 | Sports
2 | Festivals
3 | Classes
4 | Other
You would simply select the data from the table with SQL, rather than have a table that looks like:
id | word
1 | Sports|Festivals|Classes|Other
That's not how anybody designs a schema in a relational database, it totally defeats the purpose of it.
implode():
<?php
$string = implode('|',$types);
However, Incognito is right, you probably don't want to store it that way -- it's a total waste of the relational power of your database.
If you're dead-set on serializing, you might also consider using json_encode()
This one saves KEYS & VALUES
function array2string($data){
$log_a = "";
foreach ($data as $key => $value) {
if(is_array($value)) $log_a .= "[".$key."] => (". array2string($value). ") \n";
else $log_a .= "[".$key."] => ".$value."\n";
}
return $log_a;
}
Hope it helps someone.
$data = array("asdcasdc","35353","asdca353sdc","sadcasdc","sadcasdc","asdcsdcsad");
$string_array = json_encode($data);
now you can insert this $string_array value into Database
For store associative arrays you can use serialize:
$arr = array(
'a' => 1,
'b' => 2,
'c' => 3
);
file_put_contents('stored-array.txt', serialize($arr));
And load using unserialize:
$arr = unserialize(file_get_contents('stored-array.txt'));
print_r($arr);
But if need creat dinamic .php files with array (for example config files), you can use var_export(..., true);, like this:
Save in file:
$arr = array(
'a' => 1,
'b' => 2,
'c' => 3
);
$str = preg_replace('#,(\s+|)\)#', '$1)', var_export($arr, true));
$str = '<?php' . PHP_EOL . 'return ' . $str . ';';
file_put_contents('config.php', $str);
Get array values:
$arr = include 'config.php';
print_r($arr);
You can use serialize:
$array = array('text' => 'Hello world', 'value' => 100);
$string = serialize($array); // a:2:{s:4:"text";s:11:"Hello world";s:5:"value";i:100;}
and use unserialize to convert string to array:
$string = 'a:2:{s:4:"text";s:11:"Hello world";s:5:"value";i:100;}';
$array = unserialize($string); // 'text' => 'Hello world', 'value' => 100
there are many ways ,
two best ways for this are
$arr = array('a' => 1, 'b' => 2, 'c' => 3, 'd' => 4, 'e' => 5);
echo json_encode($arr);
//ouputs as
{"a":1,"b":2,"c":3,"d":4,"e":5}
$b = array ('m' => 'monkey', 'foo' => 'bar', 'x' => array ('x', 'y', 'z'));
$results = print_r($b, true); // $results now contains output from print_r
Yet another way, PHP var_export() with short array syntax (square brackets) indented 4 spaces:
function varExport($expression, $return = true) {
$export = var_export($expression, true);
$export = preg_replace("/^([ ]*)(.*)/m", '$1$1$2', $export);
$array = preg_split("/\r\n|\n|\r/", $export);
$array = preg_replace(["/\s*array\s\($/", "/\)(,)?$/", "/\s=>\s$/"], [null, ']$1', ' => ['], $array);
$export = join(PHP_EOL, array_filter(["["] + $array));
if ((bool) $return) return $export; else echo $export;
}
Taken here.
If you have an array (like $_POST) and need to keep keys and values:
function array_to_string($array) {
foreach ($array as $a=>$b) $c[]=$a.'='.$b;
return implode(', ',$c);
}
Result like: "name=Paul, age=23, city=Chicago"

How to convert this string into an array

I have a string being returned from my database that I want to use as an array. It is already in an assoc array form. Here is a sample of what this looks like so far. How would I do this?
'test1' => 'value 1',
'test1' => 'value 1a,
'test2' => 'value 2'
Ok, this is the database code:
SELECT
inventory.invId,
GROUP_CONCAT(CONCAT( '''', inventory.vehicle, ''' => ', '''', inventory.color, '''' )) AS vehicle,
vehicle.vehicle_id
FROM
inventory
Inner Join vehicle ON vehicle.invId = inventory.invId
This is the print_r from the database results
Array
(
[0] => Array
(
[system] => AR3
[vehicle] => 'geo' => 'red', 'honda' => 'blue', 'ford' => 'black'
[vehicle_id] => 1232132
)
)
I'd strongly advise against returning data in such a format. First of all, you need to take much more care creating this special format to make it parse-able. What if a value contains the character "'"? You'd get 'key' => 'value '', which will throw the whole parsing process for a loop. Secondly, it's a non-trivial form to parse and would require a lexer or using the PHP tokenizer, which is much more work than it's worth.
For transporting native structures in strings, there's a special serialized format. You're just reinventing the wheel here. Badly, I might add. :)
Just return the results as normal SELECT * FROM table … and build the array in PHP, that's the proven and fastest way to do it.
$f = array();
$a1 = explode( ',', $string );
foreach( $a1 as $s ) {
$a2 = explode( '=>', $s ) {
$a2[0] = preg_replace( "/^'/", '', $a2[0] );
$a2[0] = preg_replace( "/'\s*$/", '', $a2[0] );
$a2[1] = preg_replace( "/^\s*'/", '', $a2[1] );
$a2[1] = preg_replace( "/'$/", '', $a2[1] );
$f[$a2[0]] = $a2[1];
}
}
note: Thanks for adding the code block formatting codaddict! ... Ps agree with answer on how to return result better: this is just a literal answer to Q

Categories