$cartArray structure:
Array ( [0] => 1. X => 2. Y [2] => 3. Z [3] => 4. XX [4] => 5. YY [5] => )
$list:
$list = array(
"1.",
"2.",
"3.",
"4.",
"5."
);
Function
function alignNum($cartArray, $list)
{
foreach($cartArray as $cA)
{
echo "<br />" . $cA . "<br /><br />";
foreach($list as $l)
{
echo $l . "<br />";
echo "Type of \$l is " . gettype($l) . " and type of \$cA is " . gettype($cA) . "<br />";
$pos = strpos($cA, $l);
echo "Comparing " . $l . " to " . $cA . "<br />";
if ($pos !== true)
{
echo "<br />" . $l . " was not found in " . $cA . "<br /><br />";
continue;
}
else
{
$post_cA = str_replace("EUR", "EUR</span>", $cA);
$new_cA[] = (str_replace($l, substr($l, 0, -4) . "<span style='float: right>'", $cA)) . $post_cA;
return $new_cA;
}
}
}
}
$new_cart = alignNum($cart, $list);
So, I keep getting my custom debug message: "X was not found in Y". I.e it's not founding it X in ANY of the provided strings.
It's not a question of types either. Both are strings.
Any ideas?
EDIT: Also, note that I've censored some stuff out, since this is business related code.
It is generally a bad idea (unless you are C programmer) to compare numeric and boolean even in
if ($pos != true)
but in
if ($pos !== true)
AFAIK it will NEVER match because the variables are different types
German Arlington is actually right.
Have a look what strpos is returning:
Returns the position of where the needle exists relative to the
beginning of the haystack string (independent of offset). Also note
that string positions start at 0, and not 1.
Returns FALSE if the needle was not found.
with
if ($pos !== true)
you are asking wether strpos returned a boolean true (as you are checking typesafe with !==).
But actually strpos may have found the needle and returned i.e 2 for the position of the first match, but you asked for true.
try to check the other way round:
if (false === $pos) { // your debug message }
Related
Let's say I have a URL: https://somesite.com/0/posts/20/290/755653-Title.html How would I get these variables: /0/, /20/, /290/ ? Note they are variables, they will always be different.
I thought I could get them like so:
$url = '//somesite.com/0/posts/20/290/755653-Title.html';
var_dump(parse_url($url));
but the array doesn't show them as separate variables. Should it be done with a preg_replace instead? I don't think I know how. Thank you for your help.
One option is to use a positive lookahead with preg_match_all where you capture the pattern in a capturing group:
(?=(/\d+/))
That will match
(?= Positive lookahead, assert what is directly on the right is
(/\d+/) Match /, 1+ digits and /
) Close positive lookahead
Regex demo | Php demo
For example
$re = '~(?=(/\d+/))~m';
$str = 'https://somesite.com/0/posts/20/290/755653-Title.html';
preg_match_all($re, $str, $matches);
print_r($matches[1]);
Result
Array
(
[0] => /0/
[1] => /20/
[2] => /290/
)
If you want to get the digits only without the surrounding slashes you could add the group around the digits only
(?=/(\d+)/)
Php demo
You could use explode() and turn the string into an array divided by the "/" delimiter.
<?php
// Example 1
$url = "https://somesite.com/0/posts/20/290/755653-Title.html";
$pieces = explode("/", $url);
echo $pieces[0] . "<br />";
echo $pieces[1] . "<br />";
echo $pieces[2] . "<br />";
echo $pieces[3] . "<br />";
echo $pieces[4] . "<br />";
echo $pieces[5] . "<br />";
echo $pieces[5] . "<br />";
echo $pieces[6] . "<br />";
echo $pieces[7] . "<br />";
echo "<hr />";
// Example 2
$data = "https://somesite.com/0/posts/20/290/755653-Title.html";
list($first, $second, $third, $fourth, $fifth, $sixth, $seventh, $eighth) = explode("/", $url);
echo $first . "<br />";
echo $second . "<br />";
echo $third . "<br />";
echo $fourth . "<br />";
echo $fifth . "<br />";
echo $sixth . "<br />";
echo $seventh . "<br />";
echo $eighth . "<br />";
?>
Output:
https:
somesite.com
0
posts
20
20
290
755653-Title.html
https:
somesite.com
0
posts
20
290
755653-Title.html
We can try splitting on path separator, and then using array_filter with an inline function to retain only purely numerical components:
$str = 'https://somesite.com/0/posts/20/290/755653-Title.html';
$parts = explode("/", $str);
$parts = array_filter($parts, function($item) { return is_numeric($item); });
print_r($parts);
This prints:
Array
(
[3] => 0
[5] => 20
[6] => 290
)
Note that this approach completely avoids the use of a formal regex, which might have performance implications if you needed to do this often in your script.
I have a multi-dimensional array $games_array that looks like this:
<?php
$games_array = array(
"game-one" => array(
"name" => "Game One",
"download_id" => "gameone",
"file" => "./games/files/Game One.zip"
),
"game-two" => array(
"name" => "Game Two",
"download_id" => "gametwo",
"file" => "./games/files/Game Two.zip"
)
);
?>
For example, to access the first game's name, I'd use $games_array["game-one"]["name"] which works fine.
Okay, now to the problem: I have a value, for example gameone, that corresponds to download_id (which is a key that every game in $games_array has).
Now I want to find out the key, in this example game-one or game-two, of the array that contains this value for the key download_id. That works.
What I do in the code below is iterate over $games_array and search each game for the value (in the code below gameone). If it's found, the key for that value is returned.
The next thing I do (if ($key_found) { ...) is to try and find out the key file's value by using the array in which the value for which I originally searched was found, and save it in $file.
Unfortunately $file is always empty and I don't know why.
<?php
$key = "";
$key_found = false;
$search_for_value = "gameone"; // search for game's download id in array
$file = "";
foreach($games_array as $game_id => $game_data) {
$key = array_search($search_for_value, $game_data);
echo "Searching for value <b>" . $search_for_value . "</b> in sub-array <b>" . $game_id . "</b>...<br />";
if ($key === FALSE) {
echo "Search returned FALSE<br /><br />";
} else if ($key === NULL) {
echo "Search returned NULL<br /><br />";
} else {
echo "\$key <b>" . $key . "</b> found! <br /><br />";
$key_found = true;
}
if ($key_found) {
// Key "download_id" found. Now search the parent array for the found key and use the
// returned result as the new key to access the "file" value in the found game's id in $games_array
$file = $games_array[array_search($key, $game_id)]["file"];
echo "The key <b>" . $key . "</b> was found.<br/>";
echo "\$file = " . $file . "<br />";
echo "Exiting loop.<br /><br />";
break;
}
}
$file = $games_array[$games_data]["file"];
echo "Checking if the file \"" . $file . "\" exists...<br />";
echo (file_exists($file) ? "File \"" . $file . "\" exists." : "File \"" . $file . "\" does not exist.");
?>
I hope you understand my problem and can help me. I'd appreciate it very much... I'm really stuck here.
If you already know that you'll be searching in download_id, then you are making this code far more complicated than it needs to be. I'm not sure if there's a real answer to your question other than trying a completely different approach.
Instead of using all these array_search calls, you can directly check the value of the column you know you're looking for, like this:
foreach( $games_array as $game_id => $game_data ) {
if( $game_data["download_id"] == $search_for_value ) {
$file = $game_data["file"];
break;
}
}
Basically, I have a variable that is built from a multidimensional array via a foreach loop.
I need to somehow validate the format that it is in, although I am not to sure how to go about this since I am still quite a newbie when it comes to PHP.
This is how my string will look:
question1,answer1,answer2,answer3,answer4
question2,answer1,answer2,answer3,answer4
question3,answer1,answer2,answer3,answer4
I need to validate that exact format, being:
string[comma]string[comma]string[comma]string[comma]string
string[comma]string[comma]string[comma]string[comma]string
string[comma]string[comma]string[comma]string[comma]string
I need to validate it with a boolean variable if possible, to return true or false if it matches the format or not. These strings can contain anything such as letters, numbers, special characters, etc.
Each line will ALWAYS have 5 strings and 4 commas, never more and never less.
If needed, this is the code that builds the multidimensional array and then converts it into a string. It is grabbing an uploaded CSV file, transferring it into a multidimensional array, and then building the string afterwards. As you can see, my array is starting at 1 instead of 0, no point explaining why since that is off topic.
$csv_array = array(array());
if (!empty($_FILES['upload_csv']['tmp_name']))
{
$file = fopen($_FILES['upload_csv']['tmp_name'], 'r');
}
if($file)
{
while (($line = fgetcsv($file)) !== FALSE)
{
$csv_array[] = array_combine(range(1, count($line)), array_values($line));
}
fclose($file);
}
if(!empty($csv_array[1]))
{
foreach (array_slice($csv_array,1) as $row)
{
$all_questions = $all_questions . $row[1] . ",";
$all_questions = $all_questions . $row[2] . ",";
$all_questions = $all_questions . $row[3] . ",";
$all_questions = $all_questions . $row[4] . ",";
$all_questions = $all_questions . $row[5];
$all_questions = $all_questions . "\n";
}
}
All help is greatly appreciated.
Thanks in advance!
Sounds like a regex could do the job:
$match_ok = preg_match('/^([^,]+,){4}[^,]+$/', $test_string);
If you want to allow [string] to be empty, you may change all + to *.
Explanation: The first ^ matches the line start, then one or more characters, that are not commas, are expected followed by a comma. This sequence has to be there 4 times and has to be followed by another string not terminated by a comma. The $ matches the end of the line.
If you want to match the while multiline string, you may use:
$match_ok = preg_match('/^(([^,]+,){4}[^,]+\n){3}$/', $test_string);
(since preg_match works in multiline mode by default)
Edit 2: You may even make the regex match to a string not ending with a newline by handling the last line separately, just as it is done with the cols:
$match_ok = preg_match('/^(([^,]+,){4}[^,]+\n){2}([^,]+,){4}[^,]+$/', $test_string);
Try This simple one, May be so many other solutions possible for this
<?php
$test_string = "question1,answer1,answer2,answer3,answer4";
$newarray=explode(',',$test_string);
if(count($newarray)=='5'){
your code......;
}
?>
--------------------TRUE FALSE-------------
<?php
$test_string = "questionAsdAD1###,234234,answer2,answer3,answer4";
function ToCheckMyStrung($test_string){
$newarray=explode(',',$test_string);
if(count($newarray)=='5'){
return true;
} else {
return false;
}
}
?>
in foreach
use
implode(',',$row); for proper formatting.
You can do it while you are creating your string variable,
$count=1;
$trace=array();
if(!empty($csv_array[1]))
{
foreach (array_slice($csv_array,1) as $row)
{
$all_questions = $all_questions . $row[1] . ",";
$all_questions = $all_questions . $row[2] . ",";
$all_questions = $all_questions . $row[3] . ",";
$all_questions = $all_questions . $row[4] . ",";
$all_questions = $all_questions . $row[5];
$all_questions = $all_questions . "\n";
if($row[1]=="" || $row[2]=="" || $row[3]=="" || $row[4]=="" || $row[5]=="")
{
$trace[]=$count;
}
$count++;
}
}
and than just make use of $trace array whenever you want.
A regular expression will help you out:
$test_string = "Some,string,you,want,to,test";
if(preg_match('#^([a-zA-Z0-9]+\,)+([a-zA-Z0-9])+$#', $test_string)) {
echo 'All ok';
}
1
00:00:00,074 --> 00:00:02,564
Previously on Breaking Bad...
2
00:00:02,663 --> 00:00:04,393
Words...
i need to parse srt files with php and print the all subs in the file with variables.
i couldn't find the right reg exps. when doing this i need to take the id, time and the subtitle variables. and when printing there musn't be no array() s or etc. must print just the same as in the orginal file.
i mean i must print like;
$number <br> (e.g. 1)
$time <br> (e.g. 00:00:00,074 --> 00:00:02,564)
$subtitle <br> (e.g. Previously on Breaking Bad...)
by the way i have this code. but it doesn't see the lines. it must be edited but how?
$srt_file = file('test.srt',FILE_IGNORE_NEW_LINES);
$regex = "/^(\d)+ ([\d]+:[\d]+:[\d]+,[\d]+) --> ([\d]+:[\d]+:[\d]+,[\d]+) (\w.+)/";
foreach($srt_file as $srt){
preg_match($regex,$srt,$srt_lines);
print_r($srt_lines);
echo '<br />';
}
Here is a short and simple state machine for parsing the SRT file line by line:
define('SRT_STATE_SUBNUMBER', 0);
define('SRT_STATE_TIME', 1);
define('SRT_STATE_TEXT', 2);
define('SRT_STATE_BLANK', 3);
$lines = file('test.srt');
$subs = array();
$state = SRT_STATE_SUBNUMBER;
$subNum = 0;
$subText = '';
$subTime = '';
foreach($lines as $line) {
switch($state) {
case SRT_STATE_SUBNUMBER:
$subNum = trim($line);
$state = SRT_STATE_TIME;
break;
case SRT_STATE_TIME:
$subTime = trim($line);
$state = SRT_STATE_TEXT;
break;
case SRT_STATE_TEXT:
if (trim($line) == '') {
$sub = new stdClass;
$sub->number = $subNum;
list($sub->startTime, $sub->stopTime) = explode(' --> ', $subTime);
$sub->text = $subText;
$subText = '';
$state = SRT_STATE_SUBNUMBER;
$subs[] = $sub;
} else {
$subText .= $line;
}
break;
}
}
if ($state == SRT_STATE_TEXT) {
// if file was missing the trailing newlines, we'll be in this
// state here. Append the last read text and add the last sub.
$sub->text = $subText;
$subs[] = $sub;
}
print_r($subs);
Result:
Array
(
[0] => stdClass Object
(
[number] => 1
[stopTime] => 00:00:24,400
[startTime] => 00:00:20,000
[text] => Altocumulus clouds occur between six thousand
)
[1] => stdClass Object
(
[number] => 2
[stopTime] => 00:00:27,800
[startTime] => 00:00:24,600
[text] => and twenty thousand feet above ground level.
)
)
You can then loop over the array of subs or access them by array offset:
echo $subs[0]->number . ' says ' . $subs[0]->text . "\n";
To show all subs by looping over each one and displaying it:
foreach($subs as $sub) {
echo $sub->number . ' begins at ' . $sub->startTime .
' and ends at ' . $sub->stopTime . '. The text is: <br /><pre>' .
$sub->text . "</pre><br />\n";
}
Further reading: SubRip Text File Format
Group the file() array into chunks of 4 using array_chunk(), then omit the last entry, since it's a blank line like this:
foreach( array_chunk( file( 'test.srt'), 4) as $entry) {
list( $number, $time, $subtitle) = $entry;
echo $number . '<br />';
echo $time . '<br />';
echo $subtitle . '<br />';
}
That is not going to match because your $srt_file array might look like this:
Array
([0] => '1',
[1] => '00:00:00,074 --> 00:00:02,564',
[2] => 'Previously on Breaking Bad...'.
[3] => '',
[4] => '2',
...
)
Your regex isn't going to match any of those elements.
If your intent is to read the entire file into one long memory-hog-of-a-string then use file_get_contents to get the entire file contents into one string. then use a preg_match_all to get all the regex matches.
Otherwise you might try to loop through the array and try to match various regex patterns to determine if the line is an id, a time range, or text and do thing appropriately. obviously you might also want some logic to make sure you are getting values in the right order (id, then time range, then text).
I made a class to convert a .srt file to array.
Each entry of the array has the following properties:
id: a number representing the id of the subtitle (2)
start: float, the start time in seconds (24.443)
end: float, the end time in seconds (27.647)
startString: the start time in human readable format (00:00:24.443)
endString: the end time in human readable format (00:00:24.647)
duration: the duration of the subtitle, in ms (3204)
text: the text of the subtitle (the Peacocks ruled over Gongmen City.)
The code is php7:
<?php
namespace VideoSubtitles\Srt;
class SrtToArrayTool
{
public static function getArrayByFile(string $file): array
{
$ret = [];
$gen = function ($filename) {
$file = fopen($filename, 'r');
while (($line = fgets($file)) !== false) {
yield rtrim($line);
}
fclose($file);
};
$c = 0;
$item = [];
$text = '';
$n = 0;
foreach ($gen($file) as $line) {
if ('' !== $line) {
if (0 === $n) {
$item['id'] = $line;
$n++;
}
elseif (1 === $n) {
$p = explode('-->', $line);
$start = str_replace(',', '.', trim($p[0]));
$end = str_replace(',', '.', trim($p[1]));
$startTime = self::toMilliSeconds(str_replace('.', ':', $start));
$endTime = self::toMilliSeconds(str_replace('.', ':', $end));
$item['start'] = $startTime / 1000;
$item['end'] = $endTime / 1000;
$item['startString'] = $start;
$item['endString'] = $end;
$item['duration'] = $endTime - $startTime;
$n++;
}
else {
if ($n >= 2) {
if ('' !== $text) {
$text .= PHP_EOL;
}
$text .= $line;
}
}
}
else {
if (0 !== $n) {
$item['text'] = $text;
$ret[] = $item;
$text = '';
$n = 0;
}
}
$c++;
}
return $ret;
}
private static function toMilliSeconds(string $duration): int
{
$p = explode(':', $duration);
return (int)$p[0] * 3600000 + (int)$p[1] * 60000 + (int)$p[2] * 1000 + (int)$p[3];
}
}
Or check it out here: https://github.com/lingtalfi/VideoSubtitles
You can use this project: https://github.com/captioning/captioning
Sample code:
<?php
require_once __DIR__.'/../vendor/autoload.php';
use Captioning\Format\SubripFile;
try {
$file = new SubripFile('your_file.srt');
foreach ($file->getCues() as $line) {
echo 'start: ' . $line->getStart() . "<br />\n";
echo 'stop: ' . $line->getStop() . "<br />\n";
echo 'startMS: ' . $line->getStartMS() . "<br />\n";
echo 'stopMS: ' . $line->getStopMS() . "<br />\n";
echo 'text: ' . $line->getText() . "<br />\n";
echo "=====================<br />\n";
}
} catch(Exception $e) {
echo "Error: ".$e->getMessage()."\n";
}
Sample output:
> php index.php
start: 00:01:48,387<br />
stop: 00:01:53,269<br />
startMS: 108387<br />
stopMS: 113269<br />
text: ┘ç┘à╪د┘ç┘┌»█î ╪▓█î╪▒┘┘ê█î╪│ ╪ذ╪د ┌ر█î┘█î╪ز ╪ذ┘┘ê╪▒█î ┘ê ┌ر╪»┌ر x265
=====================<br />
start: 00:02:09,360<br />
stop: 00:02:12,021<br />
startMS: 129360<br />
stopMS: 132021<br />
text: .┘à╪د ┘╪ذ╪د┘è╪» ╪ز┘┘ç╪د┘è┘è ╪د┘è┘╪ش╪د ╪ذ╪د╪┤┘è┘à -
┌╪▒╪د ╪ا<br />
=====================<br />
start: 00:02:12,022<br />
stop: 00:02:14,725<br />
startMS: 132022<br />
stopMS: 134725<br />
text: ..╪د┌»┘ç ┘╛╪»╪▒╪ز -
.╪د┘ê┘ ┘ç┘è┌┘ê┘é╪ز ┘à╪ز┘ê╪ش┘ç ╪▒┘╪ز┘┘à┘ê┘ ┘┘à┘è╪┤┘ç -<br />
=====================<br />
it can be done by using php line-break.
I could do it successfully
let me show my code
$srt=preg_split("/\\r\\n\\r\\n/",trim($movie->SRT));
$result[$i]['IMDBID']=$movie->IMDBID;
$result[$i]['TMDBID']=$movie->TMDBID;
here $movie->SRT is the subtitle of having format u posted in this question.
as we see, each time space is two new line,
hope u getting answer.
Simple, natural, trivial solution
srt subs look like this, and are separated by two newlines:
3
00:00:07,350 --> 00:00:09,780
The ability to destroy a planet is
nothing next to the power of the force
Obviously you want to parse the time, using dateFormat.parse which already exists in Java, so it is instant.
class Sub {
float start;
String text;
Sub(String block) {
this.start = null; this.text = null;
String[] lines = block.split("\n");
if (lines.length < 3) { return; }
String timey = lines[1].replaceAll(" .+$", "");
try {
DateFormat dateFormat = new SimpleDateFormat("HH:mm:ss,SSS");
Date zero = dateFormat.parse("00:00:00,000");
Date date = dateFormat.parse(timey);
this.start = (float)(date.getTime() - zero.getTime()) / 1000f;
} catch (ParseException e) {
e.printStackTrace();
}
this.text = TextUtils.join(" ", Arrays.copyOfRange(lines, 2, lines.length) );
}
}
Obviously, to get all the subs in the file
List<Sub> subs = new ArrayList<>();
String[] tt = fileText.split("\n\n");
for (String s:tt) { subs.add(new Sub(s)); }
Okay I have a csv file that gets parsed and displayed. I want to make it searchable. So I have a form that accepts a user query and compares it to the array to find matches. Now here's what I have:
foreach( $last as $key=>$string ) {
$hits[$key] = strpos( strtolower( $string . " " . $first[$key] . " " . $middle[$key] ), $query );
}
Before this little snippet I force $query to lower also.
So basically this concatenates the full name, Last First Middle, and searches each array item for a match. Then if $hits[$key] != false I can say that there was a match there. So I go back and display that result from the main array of names. Hopefully that makes sense...
Now on the plus side, I will get many results that should show up. Like if I search jo, a list will come up with all of the Johnson last names.
The issue I'm having is results turning up that don't match the query or results not showing up when I know they are in the list of names. So I'll know smith john should return a result, but it will come back with no results.
This is the first time I've really worked on something with a search functionality so I want to do it right.
The strpos() function returns the index of matched substring, meaning it could possibly return 0:
strpos('foo', 'f'); // 0
If the substring is not found, it will return FALSE.
strpos('foo', 'z'); // FALSE
Because both 0 and FALSE are falsy values (meaning they both evaluate to boolean FALSE), you will need to use strict checking:
foreach( $last as $key=>$string ) {
$hits[$key] = strpos( strtolower( $string . " " . $first[$key] . " " . $middle[$key] ), $query ) !== FALSE;
}
Notice the strpos(...) !== FALSE instead of just strpos(...).
Edit (for #baudday):
Code:
<?php
$query = strtolower('Michael');
$last = array('Baier', 'Baker', 'Baker', 'Banfield', 'Banks', 'Barber');
$first = array('Michael', 'Michael', 'Stephanie', 'Christopher', 'Joseph', 'David');
$middle = array('Joseph', 'Daniel', 'Nicole', 'Phillip', 'Andrew', 'Daniel');
foreach ( $last as $key=>$string ) {
$haystack = $string . " " . $first[$key] . " " . $middle[$key] . " " . $first[$key] . " " . $middle[$key] . " " . $last[$key] . " " . $first[$key] . " " . $string . " " . $middle[$key];
$hits[$key] = strpos( strtolower( $haystack ), $query ) !== false;
}
foreach ($hits as $key => $matches) {
if ($matches) {
echo $last[$key] . ', ' . $first[$key] . ' ' . $middle[$key] . ' (key: ' . $key . ") matches the query.\n";
}
}
Output:
Baier, Michael Joseph (key: 0) matches the query.
Baker, Michael Daniel (key: 1) matches the query.