Get only one match with regexp - javascript

In the function below I iterate through an array (incidents) which contains of strings. The strings is describing an incident (crime or accidents) that is scrapted from another web app, and what I'm doing is dividing and counting the different crimes / accidents and placing them in an object (INCIDENT_MATCHES).
However, some of the text strings may contain of several of the keywords that I search for (e.g. both "gunfire" and "battery"), but that I don't want. Instead I just want the first found word to be counted, and if more keywords are found they should be ignored.
How could this be done?
var INCIDENT_MATCHES = {
battery: /\w*(bråk)\w*|överfall|slagsmål|slogs|misshandel|misshandlad|\w*(tjuv)\w*/ig,
burglaries: /snattade|snattare|snatta|inbrott|bestulen|stöld|\w*(tjuv)\w*/ig,
robberies: /\w*(rån)\w*|personrån|\w*(ryckning)\w*|väskryckt*/ig,
gunfire: /skottlossning|skjuten|sköt/ig,
drugs: /narkotikabrott/ig,
vandalism: /skadegörelse|klotter|\w*(klottra)\w*/ig,
trafficAccidents: /(trafik|bil)olycka|(trafik|bil)olyckor|\w*(personbil)\w*|singelolycka|kollision|\w*(kollidera)\w*|påkörd|trafik|smitningsolycka/ig,
};
var j = 0,
incidentCounts = {},
incidentTypes = Object.keys(INCIDENT_MATCHES);
incidents.forEach(function(incident) {
matchFound = false;
incidentTypes.forEach(function(type) {
if(typeof incidentCounts[type] === 'undefined') {
incidentCounts[type] = 0;
}
var matchFound = incident.match(INCIDENT_MATCHES[type]);
if(matchFound){
matchFound = true;
incidentCounts[type] += 1;
}
});
j++;
});

You can return false from the "each" handler to stop iteration.
if(matchFound){
matchFound = true;
incidentCounts[type] += 1;
return false;
}
edit — and you'll want (I think) another test outside that, at the end of the outer loop:
j++; // I don't understand what that does ...
if (matchFound) return false;

I found this solution below to work. What I did was the following:
I replaced the second forEach statement with "every"
Put "return false" inside "if(matchFound)"
Added "else { return true; }" so that the loop continues if no match is found.
The code:
incidents[2].forEach(function(incident) {
matchFound = false;
incidentTypes.every(function(type) {
if(typeof crimesPerType[type] === 'undefined') {
crimesPerType[type] = 0;
}
var matchFound = incident.match(INCIDENT_MATCHES[type]);
if(matchFound){
crimesPerType[type] += 1;
if (type == 'trafficAccidents') {
incidents[3][j].push('traffic');
}
else {
incidents[3][j].push('crime');
}
return false;
}
else {
return true;
}
});

Related

Breaking from a recursive function and returning a value in Javascript

I have written a javascript function like this . But I want when a cretain condition meet the function will not execute means it will break and return a true false like status.My code is like this
var ActionAttributes = function (data)
{
var status = true;
var attrKey = data.AttributeKey();
//Condition to exit
if (attrKey==''||attrKey==null)
{
status = false;
return false;
}
for (var i = 0; i < data.Children().length; i++)
{
var childData = data.Children()[i];
ActionAttributes(childData);
}
return status;
}
You need break condition in the for loop. You are just invoking it, handle the returned status.
var ActionAttributes = function(data) {
var status = true;
var attrKey = data.AttributeKey();
//Condition to exit
if (attrKey == '' || attrKey == null) {
status = false;
return false;
}
for (var i = 0; i < data.Children().length; i++) {
var childData = data.Children()[i];
//You need to break loop here
//Add appropriate condition here
if (ActionAttributes(childData) == false) {
return false;
}
}
return status;
}
well, that recursion is not very useful to begin with.
you call a recursion of ActionAttributes inside the loop, but never handle the returned status. So the first caller will always receive true unless the exit condition meets on the first object.
you shoul store the return from ActionAttributes into status, and then break out of the loop as soon as it's false.

Search string inside array javascript

I am looking for a simple function to check if a specific string is inside my array.
function checkRegion(departement){
var region = '';
if(alsace.indexOf(departement) != -1)
{
region = "alsace";
}
if(aquitaine.indexOf(departement) != -1){
region = "aquitaine";
}
if(auvergne.indexOf(departement) != -1){
region = "auvergne";
}
if(basseNormandie.indexOf(departement) != -1){
region = "basse-normandie";
}
if(iledefrance.indexOf(departement) != -1){
region = "ile-de-france";
}else{
region = 'undennnnnfined';
}
return region;
};
Any solution ?
Thanks
Your problem lies in the use of consecutive if statements without chaining them together to make a complete check.
Doing it your way, the code actually completely disregards all the if statements, but the last one.
So, if iledefrance.indexOf(departement) != -1 gives false, it'will always execute the code inside else, meaning it'll set region = 'undennnnnfined'.
Note:
In the code, I replaced != -1 with ~ as it makes for a somewhat more succinct code. In essence, it will convert -1 to 0, namely false.
Be sure to check out MDN's documentation for more if you are not familiar.
• 1st Option :
Try chaining your if statements together in an if/else if/else format as follows:
function checkRegion(departement){
var region = '';
if(~alsace.indexOf(departement)) {
region = "alsace";
}
else if(~aquitaine.indexOf(departement)) {
region = "aquitaine";
}
else if(~auvergne.indexOf(departement)) {
region = "auvergne";
}
else if(~basseNormandie.indexOf(departement)) {
region = "basse-normandie";
}
else if(~iledefrance.indexOf(departement)) {
region = "ile-de-france";
}
else{
region = 'undennnnnfined';
}
return region;
};
• 2nd Option :
Create two arrays:
One should contain your region arrays (alsace, aquitaine etc) &
One more containing the names of your arrays as strings, so that you can return the appropriate string based on the array that was evaluated as true.
Code:
function checkRegion(departement) {
var
regions = [alsace, aquitaine, auvergne, basseNormandie, iledefrance],
regionsNames = ["alsace", "aquitaine", "auvergne", "basseNormandie", "iledefrance"];
for (var i = 0; i < regions.length; i++) {
if (~regions[i].indexOf(departement)) {
return regionsNames[i];
}
}
return "undennnnnfined"; // If the 'for' loop doesn't return anything, it's false.
};
Demos:
Working demo with the 1st solution → here.
Working demo with the 2nd solution → here.
Snippets:
Snippet with the 1st solution:
function checkRegion(departement){
var region = '';
if(~alsace.indexOf(departement)) {
region = "alsace";
}
else if(~aquitaine.indexOf(departement)) {
region = "aquitaine";
}
else if(~auvergne.indexOf(departement)) {
region = "auvergne";
}
else if(~basseNormandie.indexOf(departement)) {
region = "basse-normandie";
}
else if(~iledefrance.indexOf(departement)) {
region = "ile-de-france";
}
else{
region = 'undennnnnfined';
}
return region;
};
var
alsace = ["Strasbourg", "Colmar"],
aquitaine = ["Gironde", "Landes", "Dordogne", "Pyrenees-Atlantiques", "Lot-et-Garonne"],
auvergne = [],
basseNormandie = [],
iledefrance = [];
alert(checkRegion("Strasbourg"));
Snippet with the 2nd solution:
function checkRegion(departement) {
var
regions = [alsace, aquitaine, auvergne, basseNormandie, iledefrance],
regionsNames = ["alsace", "aquitaine", "auvergne", "basseNormandie", "iledefrance"];
for (var i = 0; i < regions.length; i++) {
if (~regions[i].indexOf(departement)) {
return regionsNames[i];
}
}
return "undennnnnfined"; // If the 'for' loop doesn't return anything, it's false.
};
var
alsace = ["Strasbourg", "Colmar"],
aquitaine = ["Gironde", "Landes", "Dordogne", "Pyrenees-Atlantiques", "Lot-et-Garonne"],
auvergne = [],
basseNormandie = [],
iledefrance = [];
alert(checkRegion("Strasbourg"));

Trouble excluding class from jquery function

I have a function that scrambles letters based on shuffleLetters.js. It's working great, but I can't seem to exclude classes that are nested in the class that I'm targeting.
So I want to scramble the characters in my menu items. So I give them a class of .shuffle and call the function like so:
$(function(){
var container = $(".shuffle")
container.shuffleLetters();
});
Where .shuffleLetters engages the plugin. The problem is that it's scrambling all the characters that are nested within that menu item, which I don't want.
I've read about the .not method, but can't get it to work properly.
Here's what I'm trying:
<li class="shuffle">title
<li class="no-shuffle">sub-title
</li>
</li>
then I'm writing my js like so (or every possible variation of):
$(function(){
var container = $(".shuffle").not('.no-shuffle')
container.shuffleLetters();
});
This is not working though.
Can anyone point me in the right direction here, racking my brain for hours.
as always, thanks in advance!
Edit: Here's the shuffleLetters.js:
(function($){
$.fn.shuffleLetters = function(prop){
var options = $.extend({
"step" : 8, // How many times should the letters be changed
"fps" : 25, // Frames Per Second
"text" : "", // Use this text instead of the contents
"callback" : function(){} // Run once the animation is complete
},prop)
return this.each(function(){
var el = $(this),
str = "";
// Preventing parallel animations using a flag;
if(el.data('animated')){
return true;
}
el.data('animated',true);
if(options.text) {
str = options.text.split('');
}
else {
str = el.text().split('');
}
// The types array holds the type for each character;
// Letters holds the positions of non-space characters;
var types = [],
letters = [];
// Looping through all the chars of the string
for(var i=0;i<str.length;i++){
var ch = str[i];
if(ch == " "){
types[i] = "space";
continue;
}
else if(/[a-z]/.test(ch)){
types[i] = "lowerLetter";
}
else if(/[A-Z]/.test(ch)){
types[i] = "upperLetter";
}
else {
types[i] = "symbol";
}
letters.push(i);
}
el.html("");
// Self executing named function expression:
(function shuffle(start){
// This code is run options.fps times per second
// and updates the contents of the page element
var i,
len = letters.length,
strCopy = str.slice(0); // Fresh copy of the string
if(start>len){
// The animation is complete. Updating the
// flag and triggering the callback;
el.data('animated',false);
options.callback(el);
return;
}
// All the work gets done here
for(i=Math.max(start,0); i < len; i++){
// The start argument and options.step limit
// the characters we will be working on at once
if( i < start+options.step){
// Generate a random character at thsi position
strCopy[letters[i]] = randomChar(types[letters[i]]);
}
else {
strCopy[letters[i]] = "";
}
}
el.text(strCopy.join(""));
setTimeout(function(){
shuffle(start+1);
},1000/options.fps);
})(-options.step);
});
};
function randomChar(type){
var pool = "";
if (type == "lowerLetter"){
pool = "abcdefghijklmnopqrstuvwxyz0123456789";
}
else if (type == "upperLetter"){
pool = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
}
else if (type == "symbol"){
pool = ",.?/\\(^)![]{}*&^%$#'\"";
}
var arr = pool.split('');
return arr[Math.floor(Math.random()*arr.length)];
}
})(jQuery);
Try wrapping text node "title" in .shuffle li within span element
(function($){
$.fn.shuffleLetters = function(prop){
var options = $.extend({
"step" : 8, // How many times should the letters be changed
"fps" : 25, // Frames Per Second
"text" : "", // Use this text instead of the contents
"callback" : function(){} // Run once the animation is complete
},prop)
return this.each(function(){
var el = $(this),
str = "";
// Preventing parallel animations using a flag;
if(el.data('animated')){
return true;
}
el.data('animated',true);
if(options.text) {
str = options.text.split('');
}
else {
str = el.text().split('');
}
// The types array holds the type for each character;
// Letters holds the positions of non-space characters;
var types = [],
letters = [];
// Looping through all the chars of the string
for(var i=0;i<str.length;i++){
var ch = str[i];
if(ch == " "){
types[i] = "space";
continue;
}
else if(/[a-z]/.test(ch)){
types[i] = "lowerLetter";
}
else if(/[A-Z]/.test(ch)){
types[i] = "upperLetter";
}
else {
types[i] = "symbol";
}
letters.push(i);
}
el.html("");
// Self executing named function expression:
(function shuffle(start){
// This code is run options.fps times per second
// and updates the contents of the page element
var i,
len = letters.length,
strCopy = str.slice(0); // Fresh copy of the string
if(start>len){
// The animation is complete. Updating the
// flag and triggering the callback;
el.data('animated',false);
options.callback(el);
return;
}
// All the work gets done here
for(i=Math.max(start,0); i < len; i++){
// The start argument and options.step limit
// the characters we will be working on at once
if( i < start+options.step){
// Generate a random character at thsi position
strCopy[letters[i]] = randomChar(types[letters[i]]);
}
else {
strCopy[letters[i]] = "";
}
}
el.text(strCopy.join(""));
setTimeout(function(){
shuffle(start+1);
},1000/options.fps);
})(-options.step);
});
};
function randomChar(type){
var pool = "";
if (type == "lowerLetter"){
pool = "abcdefghijklmnopqrstuvwxyz0123456789";
}
else if (type == "upperLetter"){
pool = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
}
else if (type == "symbol"){
pool = ",.?/\\(^)![]{}*&^%$#'\"";
}
var arr = pool.split('');
return arr[Math.floor(Math.random()*arr.length)];
}
})(jQuery);
$(function() {
var container = $(".shuffle span:first")
container.shuffleLetters();
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js">
</script>
<ul>
<li class="shuffle"><span>title</span>
<ul>
<li class="no-shuffle">sub-title
</li>
</ul>
</li>
</ul>

Javascript Recursion returning undefined

I'm struggling in a recursive Javascript function to find a specific subdirectory. This is my code:
function navigateToParent() {
var parentFullPath = parentDirectory(); // gets the full Path String
if (parentFullPath != null) {
var parent = getDirectoryByName(parentFullPath, rootDirectory);
// set the parent directory object as the current one
currentDirectory(parent);
}
}
function getDirectoryByName(fullName, myDirectory) {
if (myDirectory.fullName == fullName) {
return myDirectory;
} else {
var subs = myDirectory.subDirectories;
for (i = 0; i < subs.length; i++) {
return getDirectoryByName(fullName,subs[i]);
}
}
}
Every directory object has the properties fullName(string),subDirectories(array of directories) and files(array of files). My aim is to get the correct directory object, where it's fullName is matching.
I know, that i have to break the for loop in some way, but i don't know how to do it exactly.
After overthinking the logic i came to this solution (seems to work):
function getDirectoryByName(fullName, myDirectory) {
if (myDirectory.fullName == fullName) {
return myDirectory;
} else {
var subs = myDirectory.subDirectories;
for (i = 0; i < subs.length; i++) {
var match = getDirectoryByName(fullName, subs[i]);
if (typeof match !== "undefined"){
return match;
}
}
}
}

Checking multiple variables' values to make sure they all match

How do I efficiently check to see if multiple variables' values all match? The following function should return true if they match and false if they don't:
function projectIsLocked (data) {
if (data.ArchiveSnapshotID === data.CurrentSnapshotID === data.LiveSnapshotID) {
return true;
}
return false;
}
I thought I could just use if (data.ArchiveSnapshotID === data.CurrentSnapshotID === data.LiveSnapshotID) but it doesn't seem to work.
Ideas for something simple?
If there are just 3 comparisons , then this should be enough.
function projectIsLocked (data) {
var archive = data.ArchiveSnapshotID;
var current = data.CurrentSnapshotID;
var live = data.LiveSnapshotID;
return (archive === current && current === live)
}
Why not push them all to an array. This way you can use as many.
function check_for_equal_array_elements(my_array){
if (my_array.length == 1 || my_array.length == 0) {
return true;
}
for (i=0;i<my_array.length;i++){
if (i > 0 && my_array[i] !== my_array[i-1]) {
return false;
}
}
return true;
}
//Example:
var my_array = [];
my_array.push(5);
my_array.push(5);
// will alert "true"
alert("all elements equal? "+check_for_equal_array_elements(my_array));
my_array.push(6);
// will alert "false"
alert("all elements equal? "+check_for_equal_array_elements(my_array));
The problem here is, that a part of the logical expression is evaluated and then compared, so data.ArchiveSnapshotID === data.CurrentSnapshotID evaluated to "true" and data.LiveSnapshotID is checked against true, which you can see here (LiveSnapshotID was changed to boolean true):
function projectIsLocked (data) {
if (data.ArchiveSnapshotID === data.CurrentSnapshotID === data.LiveSnapshotID) {
return true;
}
return false;
}
var data = { ArchiveSnapshotID: "foo", CurrentSnapshotID: "foo", LiveSnapshotID: true };
alert(projectIsLocked (data));
You might want to use something like this, which is quite extensible for even more properties.
function projectIsLocked (data) {
var props = ["ArchiveSnapshotID", "CurrentSnapshotID", "LiveSnapshotID"];
for (var i = 1; i < props.length; i++)
{
if (data[props[i]] !== data[props[i - 1]])
return false;
}
return true;
}

Categories

Resources