Javascript conditional find/replace - javascript

For my javascript project, I have a list that looks like this:
<li id="1">101.33, "book name 1"</li>
<li id="2">600.01, book name 2</li>
<li id="3">001.11, book name 3</li>
etc...
Of which I am supposed to do the following:
Remap the bullet list entries to a new (consistent) tag type (your choice – make it look pretty!).
For entries between 100 and 200, add 100 to the Dewey decimal number.
For entries between 400 and 500, add 200 to the Dewey decimal number.
Entries between 850 and 900 need to have 100 removed from the Dewey decimal number.
Entries between 600 and 650 need to have 17 added to the Dewey decimal number
For items that get changed, append “changed” to the record.
For items that do not get changed, append “no change” to the record.
For records that are incorrect, append “invalid record” to the record
But I'm not sure how to go about it. I want to target any number in the body, or within a list item. Right now I have this:
var z = document.body.li.innerHTML;
if (z >+ 100 && z <= 200)
{
var q = z + 100;
document.body.li.innerHTML=q;
}
}
Can anyone point me in the right direction of the best approach to do this in javascript? Should I be using find/replace instead?
EDIT: Attempted to amend the last ternary if else statement in David Thomas' code. Can't seem to get it to work:
//define valid record number as at-least-one-integer.at-least-one-integer
var reggie = /\d+(.)+d/
if (_newText = reggie) {
'Invalid Record';
}
else if (_newText === a[textProp]) {
'no change';
}
else(_newText != a[textProp]) {
'changed';
}
+ ')';

One approach, is the following (using plain JavaScript, albeit you'll need to use an up-to-date browser):
// first, we need to get all the 'li' items:
var lis = document.querySelectorAll('ul > li'),
// find the relevant text-property for this browser:
textProp = 'textContent' in document ? 'textContent' : 'innerText',
// empty string variable to allow assessment of changes:
_newText = '';
// Remap the bullet list entries to a new (consistent) tag type (your choice – make it look pretty!).
// do this one yourself.
// a function to zero-pad the numbers (I believe a requirement of Dewey Decimal):
function leftPadNumber(num, numLength, padChar) {
var nString = num.toString(),
major = parseInt(num, 10),
minor = parseFloat(nString.substring(nString.indexOf('.'))),
diff = numLength - major.toString().length;
if (diff > 0) {
return new Array(diff + 1).join(padChar || 0) + (major + minor);
} else {
return num;
}
}
// For entries between 100 and 200, add 100 to the Dewey decimal number.
// For entries between 400 and 500, add 200 to the Dewey decimal number.
// Entries between 850 and 900 need to have 100 removed from the Dewey decimal number.
// Entries between 600 and 650 need to have 17 added to the Dewey decimal number
// note that I've taken a very literal interpretation of 'between' (amend if necessary):
function amendedDeweyDecimal(num) {
if (num > 100 && num < 200) {
num += 100;
} else if (num > 400 && num < 500) {
num += 200;
} else if (num > 850 && num < 900) {
num -= 100;
} else if (num > 600 && num < 650) {
num += 17;
}
// happens if num falls somewhere outside of the above constraints:
return num;
}
// iterates over each element in the 'lis' nodeList/collection:
[].forEach.call(lis, function (a) {
/* replaces the found numbers ('m') in the string, using the two
functions, above, and assigns those to the _newText variable:
_newText = a[textProp].replace(/(\d{3}\.\d{2})/, function (m) {
return leftPadNumber(amendedDeweyDecimal(parseFloat(m)).toFixed(2), 3);
});
// For items that get changed, append “changed” to the record.
// For items that do not get changed, append “no change” to the record.
// returns the original text to the element, along with '(no change)'
// (if 'a[textProp]' is exactly equal to '_newText') or with '(changed)'
// (if the two variables are not identical):
a[textProp] = _newText + ' (' + (_newText === a[textProp] ? 'no change' : 'changed') + ')';
});
// For records that are incorrect, append “invalid record” to the record
// I have absolutely no idea how to assess an 'incorrect' record.
JS Fiddle demo.
References:
Array.prototype.forEach().
document.querySelectorAll().
Number.toFixed().
Number.toString().
String.parseFloat().
String.parseInt().
String.replace().

try jQuery .each
$('li').each(function(index, value) {
var val = $(this).text().split(','); //split into array
if (index >= 100 && index < 200) {
//do stuff
}
if (index >= 400 && index < 500) {
//do stuff
}
//etc
});

Regardless if you want to solve this using pure JavaScript or a helper library (like jQuery for example), i would suggest to disassemble your problem into smaller tasks and solve them one by one. At the end they will fit one into another and will build the complete solution. I would have started with three simple functions (reading your description they will be needed often):
the ability to list all LI elements separately
extract the number from the LI content
check if the number in in a given range
The code can look like this:
// count of all LI items
var elements = 0;
// fetch LI item one at a time
var element = document.getElementById(elements+1);
while (element != undefined) {
// get the number
var number = Number(getNumber(element.innerHTML));
// do something with number and or LI element
if (inRange(number, 100, 200)) { /* add 100 ...*/ } // and so on
// go to next element
elements++;
element = document.getElementById(elements+1);
}
function getNumber(elementContent) {
return elementContent.split(",")[0]; // TODO error handling
}
function inRange(number, min, max) {
return (number >= min) && (number <= max);
}
You can introduce simple objects and arrays to store information and states to track the changes of your content.

Related

Random Number List Missing Number 1

I have an issue with a function I have written: although it mostly works, there is one issue where sometimes the number 1 isn't added to the list. The code is supposed to make a list of numbers from 1 - 10, however the number 1 is sometimes missing, where I presumably the issue is it is being overwritten when number 10 is already there before number 1
The code is written using the Code.org AppLab, written in a pseudo-code that is similar to JavaScript.
function randomizer(stringName, numbersShuffled) {
//This creates a string of Numbers that will eventually be converted to a list
for (var i = 0; i < numbersShuffled; i++) {
var tempNum = randomNumber(1, numbersShuffled);
console.log(numbersShuffled);
if (stringName.includes(tempNum)) {
console.log(stringName);
if (tempNum == 1 && stringName.includes(10)) {
tempNum = randomNumber(1, numbersShuffled);
}
while ((stringName.includes(tempNum))) {
tempNum = randomNumber(1, numbersShuffled);
}
}
stringName = (stringName + " ") + tempNum;
}
console.log(stringName);
The issue is that usually the number 1 is missing if number 10 is already in place in the list.enter code here

Algorithm that involves rounding and multiples

So I have a problem where I have an array of some length (usually long). I have an initial start index into that array and a skip value. So, if I have this:
var initial = 5;
var skip = 10;
Then I'd iterate over my array with indexes 5, 15, 25, 35, etc.
But then I may get a new start value and I need to find the closest value to the initial plus or minus a multiple of the skip and then start my skip. So if my new value is 23 then I'd iterate 25, 35, 45, etc.
The algorithm I have for this is:
index = (round((start - initial) / skip) * skip) + initial
And then I need a check to see if index has dropped below zero:
while(index < 0) index += skip;
So my first question is if there's a name for this? A multiple with random start?
My second question is if there's a better way? I don't think what I have is terribly complicated but if I'm missing something I'd like to know about it.
If it matters I'm using javascript.
Thanks!
Edit
Instead of
while(index < 0) index += skip;
if we assume that both initial and skip are positive you can use:
if (index < 0) index = initial % skip;
To get the closest multiple of a number to a test number: See if the modulo of your test number is greater than number/2 and if so, return number - modulo:
function closestMultiple(multipleTest,number)
{
var modulo = multipleTest%number;
if(0 == modulo )
{
return multipleTest;
}
else
{
var halfNumber = number/2;
if(modulo >= halfNumber)
{
return multipleTest + (number-modulo);
}
else
{
return multipleTest - modulo;
}
}
}
To check if a number is a multiple of another then compare their modulo to 0:
function isMultiple(multipleTest,number)
{
return 0 == multipleTest%number;
}
You might want to add some validations for 0 in case you expect any inside closestMultiple.
The value of index computed as you put it
index = round((start - initial)/skip) * skip + initial
is indeed the one that minimizes the distance between the sequence with general term
aj = j * skip + initial
and start.
Therefore, index can only be negative if start lies to the left of
(a-1 + a0)/2 = initial - skip/2
in other words, if
start < initial - skip/2.
So, only in that case you have to redefine index to 0. In pseudo code:
IF (start < (initial - skip/2))
index = 0
ELSE
index = round((start - initial)/skip) * skip + initial
Alternatively, you could do
index = round((start - initial)/skip) * skip + initial
IF index < 0 THEN index = 0
which is the same.
No while loop required:
function newNum(newstart, initial, skip) {
var xLow = newstart + Math.abs(newstart - initial) % skip;
var xHi = newstart + skip;
var result = (xLow + xHi) / 2 > newstart ? xLow : xHi;
if (result < 0) result += skip;
return result;
}
Take the distance between your new starting point and your initial value, and find out what the remainder would be if you marched towards that initial value (Modulus gives us that). Then you just need to find out if the closest spot is before or after the starting point (I did this be comparing the midpoint of the low and high values to the starting point).
Test:
newNum(1, 20, 7) = 6
newNum(-1, 20, 7) = 6
newNum(180, 10, 3) = 182
(Even though you stated in your comments that the range of the new starting point is within the array bounds, notice that it doesn't really matter).

Jquery selecting text between parentheses in an array

I have an array based on selected values from multiple select boxes:
Term 03 (-1000),1 (+1000),Price (+3000),1 (+1500),--,--,--,--,--,--,--,--,--,--,--,--,--,--,--,--,--,--
Comma-separated. As you can see, some values have text in parentheses. I need to take these values in parentheses and sum them, therefore the + and - characters should remain.
Values (+1000), (+3000), (-1000) represent changes of price: + indicates the product will be more expensive, - represents the product will be cheaper. The result of this should be a number that indicates change of the price - e.g. 1500 - the product will cost more than basic price, or e.g. -3000 - the product will be cheaper.
Thanks in advance.
Tom
You have comma-separated values, with numbers in them to extract. Start by splitting the input to an array, then for each item, extract the value using regexp for example:
/\(([+-])(\d+)\)/ //will search for a sign (+/-) and a number between parenthesis
applied to an item will result in an array having the sign in second position and the number in 3rd position
/\(([+-])(\d+)\)/.exec('Term 03 (-1000)') //--> ['Term 03 (-1000)', '-', '1000']
Use reduce to sum the all with consideration to the sign:
var changes = str.split(',').reduce(function(sum, item){
var matches = /\(([+-])(\d+)\)/.exec(item);
if(matches) {
return sum + (matches[1] === '-' ? -1 : 1) * parseInt(matches[2]);
} else {
return sum;
}
}, 0));
P.S.: If you have already an array, you can remove the .split(',') part.
If you are not great with regular expressions I've made a version that does not "use" them, this way it's more readable and easier to see what's going on and how it goes about doing it. Not to say you should not use regular expressions.
For this algorithm we are basically looking through each item, checking if they have valid parentheses, then if we have + we add the value inside the parentheses, otherwise if we have - we subtract (assuming those are the only two you can have):
for(items in array) {
var firstPar = array[items].indexOf("(");
var secondPar = array[items].indexOf(")");
// Check of the item has parentheses and are like this (...)
if( (firstPar > 0 && secondPar > 0) && (secondPar > firstPar) ) {
// Get the number from the string
var value = array[items].substring(firstPar+2, secondPar);
value = parseInt(value); // To Number
if( array[items].charAt(firstPar+1) == '+')
ProductPrice += value; // If "+" add
else
ProductPrice -= value;// If "-" subtract
}
}
Example Here
Maybe something like this:
var sum = 0;
csv.replace(/\([^)]+\)/gi, function (str) { sum += parseInt(str,10); return str; }
Didn't test code. Anyway idea is to use regex to loop all parenthesis and then inside replace function, convert matched string to integer and add it to sum.
I managed to get this to work with the rather cumbersome code below. It does work with both positive and negative integers.
var result = arr.map(function (el) {
if (el.indexOf('(') > -1 && el.indexOf(')') > -1) {
return Number(el.match(/\(([\+\- 0-9]*)\)/g)[0].replace(/[\(\) ]/g , ''));
}
}).filter(function (el) {
if (typeof el !== undefined) {
return el;
}
}).reduce(function (p, c) {
return p + c;
});
DEMO
Try
var arr = "Term 03 (-1000),1 (+1000),Price (+3000),1 (+1500),--,--,--,--,--,--,--,--,--,--,--,--,--,--,--,--,--,--".split(",")
, sum = 0;
arr.map(function(v, k) {
// cast `v` value as `Number` , e.g., `[-1000, 1000, 3000, 1500]`
var n = Number(v.replace(/\w+[^\(+\d+\)]|[\(|\)]/g, "")) || null;
// add `n` Number's at `sum` , e.g., `-1000 + 1000 + 3000 + 1500` = `4500`
sum += n
});
// console.log(sum); // `4500`
var arr = "Term 03 (-1000),1 (+1000),Price (+3000),1 (+1500),--,--,--,--,--,--,--,--,--,--,--,--,--,--,--,--,--,--".split(",")
, sum = 0;
arr.map(function(v, k) {
// cast `v` value as `Number` , e.g., `[-1000, 1000, 3000, 1500]`
var n = Number(v.replace(/\w+[^\(+\d+\)]|[\(|\)]/g, "")) || null;
// add `n` Number's at `sum` , e.g., `-1000 + 1000 + 3000 + 1500` = `4500`
sum += n
});
document.write(sum) // `4500`
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>

Find the biggest number using javascript

I need to find the biggest number in a webpage (it is not my webpage).
Do I need javascript?
First I need to get the values from all the SPAN.f elements. Then, I must to compare the numbers into them to find out the biggest value.
How?
Let's say I've got 220 - 340 - 480 × 360 - 25/7/2012 from all the SPAN.f elements.
I need 480 to be highlighted, but I don't want /2012 to be highlighted because is part of the date. I mean, I want to highlight the 480, not the /2012.
I use GreaseMonkey with Firefox Nightly 22
THIS IS THE SCRIPT, but it does not work for me:
// ==UserScript==
// #name MAX NUMBER in page
// #include https://www.google.com/search*
// #version 1
// #grant none
// ==/UserScript==
var spans = document.querySelectorAll("SPAN.f");
var max = -Infinity;
var maxSpan;
Array.prototype.forEach.call(spans, function(span) {
var val = Number(span.textContent);
if (max < val)
{
max = val;
maxSpan = span;
}
});
if (maxSpan) maxSpan.style.backgroundColor = "yellow";
Try the code in the page into this link:
https://www.google.com/search?hl=es&tbs=sbi%3AAMhZZitcQmshs1XQVAv0-EH8Ix_18bqev3_1smHm0uRMYGzjaSYpDr6KHQ_1tWEwNyvZGPus4-VWnfO9P9071ZllBMIC3amGAveNcz_1uYWteP9OKZ1Si1Yz0urBuyIWQbBTQIue4Gntn5J8FIxaLI1kEHMdI2BIh6mrM6YGiMBT6DJyLlW4K-1kE0n_1d2fnXoNxKDd4jM034f9ctLfUYb4WvSaptVZknw_1jhHBFu9HeINrN15ha7k9Kzz1Ifm_1P5y7Vxws_1Qjr48P-rXcoqneksiRnfQyXwTGJeuMAD0wtgNnXubqYgzrPkxbZ-BonJ9Hgxvy5pv6lfEsGIuNzrtxd6QFdDKAP5keREmQ&ei=vTkuU87gBKay2wWU0IHoBg&ved=0CAgQiBw&biw=1024&bih=624&dpr=1
24/Dec/1789 is not a valid number, but should be a string, the others are numbers, and you can do
var biggest = Math.max(100, 220, 340);
If what you've got is a string, you could do
var str = '100 - 220 - 340 - 24/Dec/1789';
var biggest = Math.max.apply(null, str.split('-').filter(function(x) {
return !isNaN(x);
}));
FIDDLE;
I imagine you mean finding the largest number contained in SPAN elements having the class f (this is what the syntax SPAN.f stands for).
If so you don't need a regular expression and you don't even need to sort the values. Just iterate once over each value to find the smallest one.
Something like this:
var spans = document.querySelectorAll("SPAN.f");
var max = -Infinity;
var maxSpan;
Array.prototype.forEach.call(spans, function(span) {
var val = Number(span.textContent);
if (max < val)
{
max = val;
maxSpan = span;
}
});
if (maxSpan) maxSpan.style.backgroundColor = "yellow";
Fiddle: http://jsfiddle.net/C35W6/

javascript variable > than number

What I am tying to find is:
"if div contains '(a number greater than 1600 x a number greater than 1063)' alert success else alert error"
if (($('div:contains("(/*number greater than 1600*/ x /*number greater than 1063*/)")').length > 0)) {
alert("SUCCESS");
}
else {
alert("ERROR");
}
I thought I could use variables like
var w > 1600
var h > 1063
and then put them in like:
$('div:contains("('+ w + 'x' + h + ')")')
but that doesn't seem to work
Any ideas?
If your goal is to find all matching divs, you have to do a bit more work. Not a lot, but a bit:
var w = 1600;
var h = 1063;
// Find all divs and filter them
var matchingDivs = $("div").filter(function() {
// Does this div's text match the form (1601 x 1064)?
// If so, grab the numbers.
var match = /^\((\d+) x (\d+)\)$/.exec($(this).text());
if (match) {
// Yes, it does, do the numbers fit?
if (parseInt(match[1], 10) > w && // [1] = the first capture group
parseInt(match[2], 10) > h) { // [2] = the second capture group
// Keep this div
return true;
}
}
// Don't keep this div
return false;
});
If a div contains a number and nothing else, you can get it like this:
var num = Number($("#myDiv").text());
Or you can use the somewhat terser unary plus:
var num = +($("#myDiv").text());

Categories