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 17 days ago.
Improve this question
I'm trying to convert seats to an array in the controller.
this is how the seats data is sent to the controller
seats
:
"B7D7G10"
i want to convert it to look something like this "B7 , D7 , G10" and I want to match the seats data with my seats table so i can change the seats values in the seats table
This is my jQuery function.
$("#purchase").on("click",function() {
var data = {
seats: $(".seats-selected").text(),
seats_id: $(".seats-selected").data('sid'),
theatre_id: $("#theatres").data('tid'),
movie_id: $(".movie_id").val(),
movie: $("#m-title").text(),
theatre: $("#theatres").text(),
date: $("#date").text(),
time: $("#time").val(),
total_price: $("#total-p").text(),
};
$.ajaxSetup({
headers: {
'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')
}
});
$.ajax({
type: "POST",
url: "/send-email",
data: data,
success: function(response) {
alert("Your Theatre" + data.theatre + "\n" + data.seats_id + "\n" + data.date + "\n" + data.time + "\n" + data.total_price + "\n" );
}
});
});
This is my controller:
$seats = $request->seats;
$theatre_id = $request->theatre_id;
$date = $request->date;
$time = $request->time;
$movie_id = $request->movie_id;
$total_price = $request->total_price;
$bookings = bookings::where('theatre_id', $theatre_id)
->where('date', $date)
->where('time', $time)
->where('movie_id', $movie_id)
->get();
$reserved_seats = $bookings->pluck('seat_number')->toArray();
$seat = seats::where('seat_number', $request->seats_id)
->where('theatre_id', $theatre_id)
->where('movie_id', $movie_id)
->first();
if ($seat && !in_array($seat->id, $reserved_seats)) {
$seat->available = 0;
$seat->save();
// add the booking to the bookings table
$booking = new bookings;
$booking->theatre_id = $theatre_id;
$booking->movie_id = $movie_id;
$booking->seat_number = explode(',',$seats);
$booking->date = $date;
$booking->time = $time;
$booking->total_price = $total_price;
$booking->user_id = auth()->id();
$booking->save();
I tried every method implode, explode, array_map, everything it won't work if i just leave it be it will only change the value of the first seat. What I wanna do is save the values in bookings table (seat_number column) e.g like this: A1, B9, G10 and match the seats the AJAX request is sending to the controller from the seats table and change its available value to 0.
If you need to separate the string with no delimiting characters, then split on the zero-width space after each sequence of numbers.
\K forgets the previously matched characters so that they are not lost in the splitting process. preg_split()'s advantage over preg_match_all() is that preg_split() only creates a flat array whereas preg_match_all() creates a 2d array -- of which only its first row is used.
Code: (Demo)
$seats = "B7G12D9";
var_export (
preg_split('/\d+\K/', $seats, 0, PREG_SPLIT_NO_EMPTY)
);
Output:
array (
0 => 'B7',
1 => 'G12',
2 => 'D9',
)
Here's the implementation of the same pattern on a different string for a different effect.
It's easy enough to split up a string like B7D9H12 with a regular expression.
In PHP you'd have
<?php
$seats = "B7G12D9";
$pat = "/([A-Z]\d+)/"; // Search for A to Z followed by one or more digits and capture
preg_match_all($pat, $seats, $matches);
$seatArray = $matches[0]; // Extract the captured data from the $matches array
var_dump($seatArray);
Giving an array:
array(3) {
[0]=>
string(2) "B7"
[1]=>
string(3) "G12"
[2]=>
string(2) "D9"
}
You can do something similar in Javascript if you prefer.
See https://3v4l.org/bfZka
Related
I'm trying to mask a portion of a string using JavaScript.
e.g. Mask second and third segment of credit-card number like this using regex:
4567 6365 7987 3783 → 4567 **** **** 3783
3457 732837 82372 → 3457 ****** 82372
I just want to keep the first 4 numbers and the last 5 characters.
This is my first attempt: /(?!^.*)[^a-zA-Z\s](?=.{5})/g
https://regex101.com/r/ZBi54c/2
You can try this:
var cardnumber = '4567 6365 7987 3783';
var first4 = cardnumber.substring(0, 4);
var last5 = cardnumber.substring(cardnumber.length - 5);
mask = cardnumber.substring(4, cardnumber.length - 5).replace(/\d/g,"*");
console.log(first4 + mask + last5);
You could slice the first four digits and apply a replacement for the rest.
console.log(
['4567 6365 7987 3783', '3457 732837 82372'].map(
s => s.slice(0, 4) + s.slice(4).replace(/\d(?=.* )/g, '*')
)
);
The answer apparently satisfies the OP. Here is another solution using only Regexes:
function starry(match, gr1, gr2, gr3) {
var stars = gr2.replace(/\d/g, '*');
return gr1 + " " + stars + " " + gr3;
}
function ccStarry(str) {
var rex = /(\d{4})\s(\d{4}\s\d{4}|\d{6})\s(\d{4}|\d{5})/;
if (rex.test(str))
return str.replace(rex, starry);
else return "";
}
var s1 = "4567 6365 7987 3783";
var s2 = "3457 732837 82372";
var s3 = "dfdfdf";
console.log(ccStarry(s1));
console.log(ccStarry(s2));
console.log(ccStarry(s3));
This ensures that the pattern matches before trying any replacements. For example, in the third test case, it returns an empty string. The pattern can be updated to match other credit card patterns besides the ones given in the question.
I would like to elaborate more on the answer from #Nina Scholz, I use .slice() in the following sample code for masking the variable in 2 condition.
Just a simple variable var n = '12345567890'
Array object
// Single number
var n = '601115558888';
var singleNumber = n.slice(0, 4) + n.slice(4, n.length -4).replace(/\d/g,'*') + n.slice(n.length -4);
console.log(singleNumber);
// array of object
var obj = [{
contacts_name: 'Jason',
contacts_num : '651231239991'
},
{
contacts_name: 'King',
contacts_num : '60101233321'
}];
// Mask for the middle number, showing the first4 number and last4 number
// and replace the rest number with *
var num = obj.map((element, index) =>
element.contacts_num.slice(0,4)
+ element.contacts_num.slice(4, element.contacts_num.length-4).replace(/\d/g, '*')
+ element.contacts_num.slice(element.contacts_num.length -4)
);
console.log(num);
If it's JavaScript doing the regex masking, you've already failed because JS should never need to know the original card number, except when you've just received it from the user and are sending it to the server for the first time, in which case you shouldn't be masking it anyway so the user can check for typos.
I can't really help you there, you've already failed in the worst way.
Server-side, if the number is already broken into spaces*, then one option is: (in PHP but the same idea applies to all)
$parts = explode(" ",$fullnumber);
$first = array_shift($parts);
$last = array_pop($parts);
$middle = implode(" ",$parts);
$mask = preg_replace("/\d/","*",$middle);
$result = "$first $mask $last";
* it shouldn't be
Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 6 years ago.
Improve this question
This is a new edit to my question, hopefully it will meet the criteria and be considered eligible.
First, I managed to solve the problem. I will now describe the situation and what I think the solution that solve the problem.
My code gets a string (a call number) as an input, re-formats it, parse it to float, and return the call number location within a given set of ranges.
The code is composed of two functions: 1. formatCallNumber(callNum) which does the text manipulation to the input. 2. SortCallNum(callNumInput) - responsible on the sorting to ranges part.
The problem was in passing values of call number ranges from the sorting function (no.2) to the formatting function (no.1). Although I parsed those values as strings in the sorting function, the .replace function produced an error. The solution that I (think) worked, was to parse the values to strings in the formatting function.
The code of the two functions below is updated and seems to be working as expected:
function 1 - formatting function:
function formatCallNumber(callNum){
var formatedCallNum = String(callNum);
formatedCallNum = formatedCallNum.replace(/\D/g,''); // remove all but digits chars from the string (whitespace, dots, etc)
formatedCallNum = "0." + formatedCallNum; // add "0." to the callNumber string
formatedCallNum = parseFloat(formatedCallNum); // parse as float - so it could be compared with other decimals
return (formatedCallNum);
}
Function 2 - the sorting function:
function SortCallNum(callNumInput){
// data [test only]
var shelves = {
"S1" : {"callStart":"100","callEnd": "223.456", "id": 1},
"S2" : {"callStart":"223.457","callEnd": "334", "id": 2},
"S3" : {"callStart":"335","callEnd": "535", "id": 3},
"S4" : {"callStart":"536","callEnd": "638", "id": 4},
"S5" : {"callStart":"639","callEnd": "847", "id": 5}
};
var matchId = "";
document.getElementById("somthing").innerHTML += "you typed the number: " + callNumInput; // output of callNumInput (as inserted by user)
formatedCallNum = formatCallNumber(callNumInput);
// traverse into shelves object : iteration of objects (key = s1-s5)
for (var key in shelves) {
if (shelves.hasOwnProperty(key)) {
matchId = shelves[key].id;
document.getElementById("somthing").innerHTML += "<br>" + (" -- " + "CallEnd is: " + " -- " + shelves[key].callEnd); // display values of object shelves.key.callend
document.getElementById("somthing").innerHTML += "<br>" + (" -- " + "CallStart is: " + " -- " + shelves[key].callStart); // display values of object shelves.key.callend
var formatedCallRangeStart = formatCallNumber(shelves[key].callStart);
var formatedCallRangeEnd = formatCallNumber(shelves[key].callEnd);
console.log(formatedCallRangeStart);
console.log(formatedCallRangeEnd);
if ((formatedCallNum <= 0) || (formatedCallNum > 1)){alert('call number not in proper range'); break;}
if ((formatedCallRangeStart <= formatedCallNum)&&(formatedCallRangeEnd >= formatedCallNum)){break;}
}
}
Thanks for all the help.
As I can see, everythign should work as expected. It's important to pass a string into SortCallNum, and not a number.
function SortCallNum(callNumInput){
// data [test only]
var shelves = {
"S1" : {"callStart":100,"callEnd": "223", "id": 1},
"S2" : {"callStart":224,"callEnd": "334", "id": 2},
"S3" : {"callStart":335,"callEnd": "535", "id": 3},
"S4" : {"callStart":536,"callEnd": "638", "id": 4},
"S5" : {"callStart":639,"callEnd": "847", "id": 5}
};
var matchId = "";
document.getElementById("somthing").innerHTML += "you typed the number: " + callNumInput; // output of callNumInput (as inserted by user)
formatedCallNum = formatCallNumber(callNumInput);
// traverse into shelves object : iteration of objects (key = s1-s5)
for (var key in shelves) {
if (shelves.hasOwnProperty(key)) {
matchId = shelves[key].id;
document.getElementById("somthing").innerHTML += "<br>" + (" -- " + "CallEnd is: " + " -- " + shelves[key].callEnd); // display values of object shelves.key.callend
document.getElementById("somthing").innerHTML += "<br>" + (" -- " + "CallStart is: " + " -- " + shelves[key].callStart); // display values of object shelves.key.callend
var formatedCallRangeStart = String(shelves[key].callStart);
formatedCallRangeStart = formatCallNumber(formatedCallRangeStart);
var formatedCallRangeEnd = String(shelves[key].callEnd);
formatedCallRangeEnd = formatCallNumber(formatedCallRangeEnd);
matchId = shelves[key].id;
if ((formatedCallRangeStart <= formatedCallNum)&&(formatedCallRangeEnd >= formatedCallNum)){
break;
}
}
}
alert (matchId);
}
function formatCallNumber(callNum){
// callNum = prompt('enter a call number: ');
formattedCallNum = callNum.replace(/\D/g,''); // remove all but digits chars from the string (whitespace, dots, etc)
formattedCallNum = "0." + formattedCallNum; // add "0." to the callNumber string
formattedCallNum = parseFloat(formattedCallNum); // parse as float - so it could be compared with other decimals
return (formattedCallNum);
}
SortCallNum('1337')
<div id="somthing"></div>
So, this would work SortCallNum('1337'), this not SortCallNum(1337)...
Another possible cause is that you trust the return-value from prompt blindly.
<button type="button" onclick="var callNumInput = prompt('enter a call number: '); SortCallNum(callNumInput);"> SortCallNum(test)</button>
When the user clicks the OK button, text entered in the input field is returned. If the user clicks OK without entering any text, an empty string is returned. If the user clicks the Cancel button, this function returns null.
https://developer.mozilla.org/en-US/docs/Web/API/Window/prompt#Example
A bit of sanitization should help:
if (callNumInput == null) {
throw new Error('You have to insert a number between 0 and 999.')
}
I'd like to have on an ecommerce product page the simple "in stock" or "out of stock" message, but the ERP solution that I've to use only permit to retrive from its db the number of items currentrly in stock.
I can only use JS, so I'm thinking to a small function that will search for the string I have, extract only the number, do an if/else in order to replace a trigger id with the proper content.
here the content of the function:
var strAval = strAval.search (/\<div id\=\"\#avail\" class\=\"hidden\"\>/ + /\d+/ + /<\/div>/);
var strAval2 = strAval.substring (32,-6);
if (strAval2 > 0) {
var str = document.getElementById("#in-stock").innerHTML;
var res = str.replace("#in-stock","IN STOCK");
document.getElementById("#in-stock").innerHTML = res;
}
else {
var str = document.getElementById("#in-stock").innerHTML;
var res = str.replace("#in-stock","OUT OF STOCK");
document.getElementById("#in-stock").innerHTML = res;
}
the string that I've into the html is:
<div id="#avail" class="hidden">329</div>
where "329" is an example - this number is variable from 1 to 4 digits [ 0 - 12 - 329 - 2654 ]
There's something wrong, but I don't know what.
I'm learning JS, so I'm really new to it.
Thanks to all.
I know there are existing some Questions about Chunking a mysql array in php, but my problem is, that I want to keep the output in JSON.
Scenario:
I want to get data from mysql, do some stuff with it ( like time formatting ) and output it in JSON.
The JSON data is parsed in the browser and visualized over a javascript chart.
Problem:
All of the above is working, but because of the huge amount of data, I'm getting an out of memory error, when I select bigger date ranges to output.
The Idea of directly sending out each x-lines of data is not working because of the JSON format it needs to be. Several JSON chunks won't work, it needs to be one for the chart.
So in the end I need to chunk the data but keep it as one big JSON.
(And setting up the memory limit is not really a solution.)
Ideas:
One Idea would be, to let the browser chunk the date range and ask the data as chunks & then put them together.
Of course this would work, but if there is a way to do this server side, it would be better.
Code:
private function getDB($date1, $date2){
$query = 'SELECT * FROM `db1`.`'.$table.'` WHERE `date` BETWEEN "'.$date1.'" AND "'.$date2.'" order by `date`;';
// date = datetime !
$result = $this->db->query($query);
$array = array();
while ( $row = $result->fetch_assoc () ) {
$array[] = array( strtotime($row[ 'date' ])*1000 , (float)$row[ 'var' ] );
// the formatting needs to be done, so the chart accepts it..
}
$result->close();
return json_encode($array);
}
Since this is not an option,
ini_set("memory_limit","32M")
perhaps you can add LIMIT to the function paramaters and query:
private function getDB($date1, $date2, $start, $pageSize){
$query = 'SELECT * FROM `db1`.`'.$table.'` WHERE `date` BETWEEN "'.$date1.'" AND "'.$date2.'" order by `date` LIMIT $start, $pageSize;';
// date = datetime !
$result = $this->db->query($query);
$array = array();
while ( $row = $result->fetch_assoc () ) {
$array[] = array( strtotime($row[ 'date' ])*1000 , (float)$row[ 'var' ] );
// the formatting needs to be done, so the chart accepts it..
}
$result->close();
return json_encode($array);
}
Then setup a for loop in javascript, call this with Ajax, incrementing the $start variable each time.
Store each responseText.substr(1).substr(-1) in an array.
When the responseText is "", all of the records have been returned.
.join the array with a comma, then add a new opening and closing "{ }", and you should have a JSON equivalent to all records.
Minimal parsing, and you'll be using built-in functions for most of it.
var startRec=0;
var pageSize=50;
var xmlhttp=new XMLHttpRequest();
var aryJSON=[];
var JSON;
xmlhttp.onreadystatechange=function(){
if (xmlhttp.readyState==4 && xmlhttp.status==200){
if(xmlhttp.responseText==""){ //Might need to check for "{}" here instead of ""
//All records are received
JSON="{" + aryJSON.join(",") + "}";
aryJSON=[];
startRec=0
}else{
aryJSON.push(xmlhttp.responseText.substr(1).substr(-1));
startRec+=pageSize;
getNextPage();
}
}
}
function getNextPage(){
xmlhttp.open("GET","your.php?start=" + startRec + "&pageSize=" + pageSize,true);
xmlhttp.send();
}
I would recommend that you have the server send the browser exactly what it needs to create the table. Parsing can be a heavy task, so why have the client do that lifting?
I would have your backend send the browser some kind of data structure that represents the table (i.e. list of lists), with all the formatting already done. Rendering the table should be faster and less memory-intensive.
One way of answer would be, to do the chunking on the server, by giving out the JSON, removing the leading [ & ].
#apache_setenv('no-gzip', 1);
#ini_set('zlib.output_compression', 0);
#ini_set('implicit_flush', 1);
$array = array();
echo '[';
$started = false;
while ( $row = $result->fetch_assoc () ) {
$array[] = [ strtotime($row[ 'datetime' ])*1000 , (float)$row[ 'var' ] ];
if(sizeof($array) == 1000){
if($started){
echo ',';
}else{
$started = true;
}
echo substr(substr(json_encode($array),1), 0, -1);
// converting [[datetime1, value1],[datetime2, value2]]
// to [datetime1, value1],[datetime2, value2]
ob_flush();
$array = array();
}
}
if($started)echo ',';
$this->flushJSON($array);
echo ']';
flush();
$result->close();
This is working and reducing the ram usage to 40%.
Still it seems that Apache is buffering something, so the ram usage increases over the time, the script is running. (Yeah, the flush is working, I debugged that, that's not the problem.)
But because of the remaining increase, the fastest way to achieve a clean chunking is to do this like alfadog67 pointed it out.
Also, to mention it, I had to disable the output compression, otherwise apache wouldn't flush it directly..
I have a table like this I'd like to sort :
| Name | Case |
| John | X-123/08 P|
| Bob | X-123/09 |
| Dylan | X-45/10 |
I want to sort the Case colum by case's year then case's number knowing that the format is always "X-(1 to 4 digits for case's number)/(case's year on 2 digits) (sometimes some text)". It's possible that after the year's case I have some text but it shoud be ignored for sorting.
I am using tablesorter jQuery's plugin and I am struggling to add a custom parser for this.
Thanks for your help !
EDIT : Here's what I'm trying to do :
jQuery.tablesorter.addParser({
// set a unique id
id: 'case',
is: function(s) {
return false;
},
format: function(s) {
// format your data for normalization
return s.replace(/^X-\d{1,4}\/(\d{2}).*$/, '$1') + ('000' + s.replace(/^X-(\d{1,4})\/\d{2}.*$/, '$1')).substr(-4);
},
// set type, either numeric or text
type: 'text'
});
It's working great until I encounter a case with 2 digits which is then ranked greater than a 3 digits one and I don't understand why ...
"X-458/09 P" is sorted smaller than "X-48/09" . I'll try some debug to see what really happens.
EDIT 2 : Also tried the second answer :
jQuery.tablesorter.addParser({
// set a unique id
id: 'case',
is: function(s) {
return false;
},
format: function(s) {
var m = s.match(/X\-(\d+)\/(\d{2}).*$/);
var affaire = m[1];
var year = m[2];
return year + '000' + affaire;
},
// set type, either numeric or text
type: 'text'
});
The result seems to be the same as the first one... I really can't understand why it sucks. Why tablesorter thinks that 488 000 10 is smaller than 49 000 10 ?!
I think you can use:
$.tablesorter.addParser({
// set a unique id
id: 'case',
is: function(s) {
// return false so this parser is not auto detected
return false;
},
format: function(s) {
// format your data for normalization
return s.replace(/^X-\d{1,4}\/(\d{2}).*$/, '$1') + ('000' + s.replace(/^X-(\d{1,4})\/\d{2}.*$/, '$1')).slice(-4);
},
// set type, either numeric or text
type: 'text'
});
EDIT:
Maybe you already tried something like this with type: 'numeric'; I'm not sure, but this may fail because parseInt('09') === 0.
EDIT 2:
Changed to reflect sorting by year, then case number.
You can use a regex to get the 2 values you're after, for example:
var columnVal = "X-123/08";
var m = columnVal.match(/X\-(\d+)\/(\d{2})$/);
var case = m[1];
var year = m[2];
After trying multiple things this one seems to work perfectly well :
jQuery.tablesorter.addParser({
// set a unique id
id: 'case',
is: function(s) {
return false;
},
format: function(s) {
var m = s.match(/X\-(\d+)\/(\d{2}).*$/);
var caseVar = '000' + m[1];
var size = caseVar.length;
caseVar= caseVar.substr(size-4, 4);
var year = m[2];
return jQuery.tablesorter.formatFloat(year + caseVar);
},
// set type, either numeric or text
type: 'numeric'
});
I did some research and it appears that the substr function with a negative value doesn't work on all browser (I'm using IE because my application must be IE compliant). I think that's the cause of my previous problems and that's why Spiny's solution wasn't working for me.
Thanks anyway to all of you for your precious help !