How can I remove occurrences with random hash? - javascript

I have a controlled <input /> in my React application where the user would type.
I want to keep track on it and replace the occurrences of $.text and $.lang to random hashes/number.
from
let string = 'I may have multiple $.text and $.lang like $.textand$.lang';
I want all occurrences of $.text and $.lang to have a random number(or anything unique):
to
updatedString = 'I may have multiple 123 and 245 like 744and111';
What I have done so far
let temp = value.split('').reverse().join(''); // reverse it to find the latest occurrence
let reText = /txet.\$/i;
let reLang = /gnal.\$/i;
let updated;
if (value.includes('$.text')) {
updated = temp.replace(reText, `${hash}#`); // replace the latest occurrence
} else {
updated = temp.replace(reLang, `${hash}#`); // replace the latest occurrence
}
updatedValue = updated.split('').reverse().join(''); // re reverse it
The issue is it replaces the but onChange RESETS the input state and it only changes the last occurrence of it.

So im doing it on click. So lets say user type something and then clicking on Replace Template button will replace the $.text and $.lang by some random number. You can insert your specific hash or number if needed.
const replaceTemplateByRandom = (val, temp) => {
while(val.indexOf(temp) != -1){
const numb = Math.floor(Math.random()*1000);
val = val.replace(temp, numb);
}
return val;
}
inside this arrow function I'm running the while loop till we find the template to replace, and replace occurrence by random number.
const replaceTemplateByRandom = (val, temp) => {
while(val.indexOf(temp) != -1){
const numb = Math.floor(Math.random()*1000);
val = val.replace(temp, numb);
}
return val;
}
function App(props){
const [val, setVal] = React.useState('default text is $.text, and language is $.lang.');
const updateVal = (e) => {
const newVal = e.target.value;
setVal(newVal);
}
const replaceTemplate = ()=>{
let currentVal = val;
currentVal = replaceTemplateByRandom(currentVal, '$.text');
currentVal = replaceTemplateByRandom(currentVal, '$.lang');
setVal(currentVal);
}
return <div>
<input type="text" value={val} onChange={updateVal} style={{"width":"100%"}}/>
<button onClick={replaceTemplate}>Replace Template</button>
</div>;
}
ReactDOM.render(<App/>, document.getElementById('app'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.3/umd/react-dom.production.min.js"></script>
<div id="app"></div>

You can make use of .replace()'s acceptance of a function for custom and dynamic substitution:
function myHashFunction(match)
{
// Uncomment this line to see the various matches coming through
//console.log(match);
// I'm just returning a random number, you need to change this to your hash algorithm
return Math.floor(Math.random() * Math.floor(999999999999));
}
let str = `I may have multiple $.text and $.lang like $.textand$.lang`;
console.log(str.replace(/\$\.(?:text|lang)/g, myHashFunction));

function myFunction() {
var theString = "How are $.you doing $.you today?";
var splitString = theString.split("$.you");
var joinedString = "";
for(index = 0; index < splitString.length-1; index++){
joinedString += splitString[index] + Math.random();
}
document.getElementById("demo").innerHTML = joinedString;
}
Something simple like this could probably do the job.
So spliting the string into an array of strings and then joining it back with a specific string.
Not React specifically, but the idea is there.

Related

How can I create unique IDs for each input field after click on "Add Row"? [duplicate]

I have a form where a user can add multiple select boxes for multiple cities. The problem is that each newly generated select box needs to have a unique id. Can this be done is JavaScript?
Here is the part of the form for selecting cities. Also note that I'm using some PHP to fill in the cities when a specific state is selected.
<form id="form" name="form" method="post" action="citySelect.php">
<select id="state" name="state" onchange="getCity()">
<option></option>
<option value="1">cali</option>
<option value="2">arizona</option>
<option value="3">texas</option>
</select>
<select id="city" name="city" style="width:100px">
</select>
<br/>
</form>
Here is the JavaScript:
$("#bt").click(function() {
$("#form").append(
"<select id='state' name='state' onchange='getCity()'>
<option></option>
<option value='1'>cali</option>
<option value='2'>arizona</option>
<option value='3'>texas</option>
</select>
<select id='city' name='city' style='width:100px'></select><br/>"
);
});
var id = "id" + Math.random().toString(16).slice(2)
another way it to use the millisecond timer:
var uniq = 'id' + (new Date()).getTime();
const uid = function(){
return Date.now().toString(36) + Math.random().toString(36).substr(2);
}
This Function generates very unique IDs that are sorted by its generated Date.
Also useable for IDs in Databases.
could you not just keep a running index?
var _selectIndex = 0;
...code...
var newSelectBox = document.createElement("select");
newSelectBox.setAttribute("id","select-"+_selectIndex++);
EDIT
Upon further consideration, you may actually prefer to use array-style names for your selects...
e.g.
<select name="city[]"><option ..../></select>
<select name="city[]"><option ..../></select>
<select name="city[]"><option ..../></select>
then, on the server side in php for example:
$cities = $_POST['city']; //array of option values from selects
EDIT 2 In response to OP comment
Dynamically creating options using DOM methods can be done as follows:
var newSelectBox = document.createElement("select");
newSelectBox.setAttribute("id","select-"+_selectIndex++);
var city = null,city_opt=null;
for (var i=0, len=cities.length; i< len; i++) {
city = cities[i];
var city_opt = document.createElement("option");
city_opt.setAttribute("value",city);
city_opt.appendChild(document.createTextNode(city));
newSelectBox.appendChild(city_opt);
}
document.getElementById("example_element").appendChild(newSelectBox);
assuming that the cities array already exists
Alternatively you could use the innerHTML method.....
var newSelectBox = document.createElement("select");
newSelectBox.setAttribute("id","select-"+_selectIndex++);
document.getElementById("example_element").appendChild(newSelectBox);
var city = null,htmlStr="";
for (var i=0, len=cities.length; i< len; i++) {
city = cities[i];
htmlStr += "<option value='" + city + "'>" + city + "</option>";
}
newSelectBox.innerHTML = htmlStr;
function uniqueid(){
// always start with a letter (for DOM friendlyness)
var idstr=String.fromCharCode(Math.floor((Math.random()*25)+65));
do {
// between numbers and characters (48 is 0 and 90 is Z (42-48 = 90)
var ascicode=Math.floor((Math.random()*42)+48);
if (ascicode<58 || ascicode>64){
// exclude all chars between : (58) and # (64)
idstr+=String.fromCharCode(ascicode);
}
} while (idstr.length<32);
return (idstr);
}
No external libraries needed. Uniqueness proved.
You could do something like this.
// Function to generate unique id
const uniqueId = (length=16) => {
return parseInt(Math.ceil(Math.random() * Date.now()).toPrecision(length).toString().replace(".", ""))
}
// ----------------------------
document.querySelector("#butt01").onclick = () => {
document.querySelector("#span01").innerHTML = uniqueId()
}
ids = []
count = 0
document.querySelector("#butt02").onclick = () => {
for (let i = 0; i< 1000; i++){
ids.push(uniqueId())
}
for (el of ids){
for (ell of ids){
if(el == ell && ids.indexOf(el) != ids.indexOf(ell)){
count += 1
}
}
}
document.querySelector("#span02").innerHTML = `Found ${count} duplicated random values.`
}
<button id="butt01">Generate</button>
<br>
<span id="span01"></span>
<br>
<hr>
<br>
<button id="butt02">Check collision potentiality in 1000 cases</button>
<br>
<span id="span02"></span>
Multiply time in milliseconds since epoch with a random value to fixed size.
Run this to see possible collisions.
You would see there are no collisions whether it is 1000, 10000 or 1000000000.
It would have a very small chance if two users generate ids at the same time and gets the rame random number.
To increase the uniqueness you could multiply date more Math.random()s.
The shortest and without libraries, also works in nodejs
crypto.randomUUID();
// 'a63ae209-ec69-4867-af8a-6f4d1efe15c6'
https://developer.mozilla.org/en-US/docs/Web/API/Crypto/randomUUID
btn.onclick = () => myID.textContent = crypto.randomUUID()
<button id="btn">Generate ID</button>
<myID id="myID"></myID>
Very short function will give you unique ID:
var uid = (function(){var id=0;return function(){if(arguments[0]===0)id=0;return id++;}})();
alert ( uid() );
In reply to #scott :
Sometime JS go very fast... so...
var uniqueId = null,
getUniqueName = function(prefix) {
if (!uniqueId) uniqueId = (new Date()).getTime();
return (prefix || 'id') + (uniqueId++);
};
I'm working on a similar problem to the OP, and found that elements of the solutions from #Guy and #Scott can be combined to create a solution that's more solid IMO. The resulting unique id here has three sections separated by underscores:
A leading letter;
A timestamp displayed in base 36;
And a final, random section.
This solution should work really well, even for very large sets:
function uniqueId () {
// desired length of Id
var idStrLen = 32;
// always start with a letter -- base 36 makes for a nice shortcut
var idStr = (Math.floor((Math.random() * 25)) + 10).toString(36) + "_";
// add a timestamp in milliseconds (base 36 again) as the base
idStr += (new Date()).getTime().toString(36) + "_";
// similar to above, complete the Id using random, alphanumeric characters
do {
idStr += (Math.floor((Math.random() * 35))).toString(36);
} while (idStr.length < idStrLen);
return (idStr);
}
You could generate an ID using a timer and avoiding duplicates using performance.now():
id = 'id' + performance.now()
dup = 'id' + performance.now()
console.log(id)
console.log(id.replace('.','')) // sexy id
console.log(id === dup) // false!
.as-console-wrapper{border-top: none !important;overflow-y: auto !important;top: 0;}
Note that the High resolution time API is available in all recent browsers.
EDIT(per Ciprian's comment): That is unfortunately not enough, performance.now() is only precise to the millisecond. Consider using it in conjuction with Math.random():
const generateId = () => `${performance.now()}${Math.random().toString().slice(5)}`.replace('.','')
let id = generateId()
let dup = generateId()
console.log(id)
console.log(id === dup) // false!
let ary = [...Array(1000)].map(_ => generateId())
console.log((new Set(ary)).size === 1000) // no dups!
.as-console-wrapper{border-top: none !important;overflow-y: auto !important;top: 0;}
put in your namespace an instance similar to the following one
var myns = {/*.....*/};
myns.uid = new function () {
var u = 0;
this.toString = function () {
return 'myID_' + u++;
};
};
console.dir([myns.uid, myns.uid, myns.uid]);
There are two packages available for this.
For short unique id generation nanoid link
import { nanoid } from 'nanoid'
const id = nanoid() // "Uakgb_J5m9g-0JDMbcJqLJ"
const id = nanoid(10) // "jcNqc0UAWK"
For universally unique id generation uuid link
import { v4 as uuidv4 } from 'uuid';
const id= uuidv4(); // quite big id
You can use the Generator function, was introduced in ES6 (https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/function*)
const idCreator = function* () {
let i = 0;
while (true) yield i++;
};
const idsGenerator = idCreator();
const generateId = () => idsGenerator.next().value;
console.log(generateId()) // 0
console.log(generateId()) // 1
console.log(generateId()) // 2
...
To avoid creating any counters and be sure that the id is unique even if there are some other components that create elements with ids on the page, you can use a random number and than correct it if it's not good enough (but you also have to set the id immediately to avoid conflicts):
var id = "item"+(new Date()).getMilliseconds()+Math.floor(Math.random()*1000);
// or use any random number generator
// whatever prefix can be used instead of "item"
while(document.getElementById(id))
id += 1;
//# set id right here so that no element can get that id between the check and setting it
Random is not unique. Times values are not unique. The concepts are quite different and the difference rears its ugly head when your application scales and is distributed. Many of the answers above are potentially dangerous.
A safer approach to the poster's question is UUIDs: Create GUID / UUID in JavaScript?
Like others said you can use a running index, or if you don't like the idea of using a variable just pull the id of the last city in the list and add 1 to its id.
Here is a function (function genID() below) that recursively checks the DOM for uniqueness based on whatever id prefex/ID you want.
In your case you'd might use it as such
var seedNum = 1;
newSelectBox.setAttribute("id",genID('state-',seedNum));
function genID(myKey, seedNum){
var key = myKey + seedNum;
if (document.getElementById(key) != null){
return genID(myKey, ++seedNum);
}
else{
return key;
}
}
Warning: This answer may not be good for the general intent of this question, but I post it here nevertheless, because it solves a partial version of this issue.
You can use lodash's uniqueId (documentation here). This is not a good uniqueId generator for say, db records, or things that will persist a session in a browser or something like that. But the reason I came here looking for this was solved by using it. If you need a unique id for something transient enough, this will do.
I needed it because I was creating a reusable react component that features a label and a form control. The label needs to have a for="controlId" attribute, corresponding to the id="controlId" that the actual form control has (the input or select element). This id is not necessary out of this context, but I need to generate one id for both attributes to share, and make sure this id is unique in the context of the page being rendered. So lodash's function worked just fine. Just in case is useful for someone else.
Simple Solution :)
const ID = (_length=13) => {
// Math.random to base 36 (numbers, letters),
// grab the first 9 characters
// after the decimal.
return '_' + Math.random().toString(36).substr(2, _length); // max _length should be less then 13
};
console.log("Example ID()::", ID())
function generateId() {
return Math.random().toString(36).substring(2) +
(new Date()).getTime().toString(36);
}
console.log(generateId())
Look at this functions, it will get ur job done.
If u want uppercase and lowercase chars in ur string:
function (length) {
var id = '';
while (id.length < length) {
var ch = Math.random()
.toString(36)
.substr(2, 1);
if (Math.random() < 0.5) {
ch = ch.toUpperCase();
}
id += ch;
}
return id;
}
Only lowercase chars:
function (length) {
var id = '';
while (id.length < length) {
id += Math.random()
.toString(36)
.substr(2, 1);
}
return id;
}
Just two cents
function makeId(tokenLen) {
if (tokenLen == null) {
tokenLen = 16;
}
var text = "";
const possible = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
for (var i = 0; i < tokenLen; ++i)
text += possible.charAt(Math.floor(Math.random() * possible.length));
return text;
}
Here's my own take at it based on the xpath of the element created :
/** Returns the XPATH of an element **/
var getPathTo = function(element) {
if (element===document.body)
return element.tagName;
var ix= 0;
var siblings= element.parentNode.childNodes;
for (var i= 0; i<siblings.length; i++) {
var sibling= siblings[i];
if (sibling===element)
// stripped xpath (parent xpath + tagname + index)
return getPathTo(element.parentNode)+ element.tagName + ix+1;
if (sibling.nodeType===1 && sibling.tagName===element.tagName)
ix++;
}
}
/** hashcode function (credit http://stackoverflow.com/questions/7616461/generate-a-hash-from-string-in-javascript-jquery **/
var hashCode = function(str) {
var hash = 0, i, chr, len;
if (str.length === 0) return hash;
for (i = 0, len = str.length; i < len; i++) {
chr = str.charCodeAt(i);
hash = ((hash << 5) - hash) + chr;
hash |= 0; // Convert to 32bit integer
}
return hash;
};
/** Genaretes according to xpath + timestamp **/
var generateUID = function(ele)
{
return hashCode(getPathTo(ele)) + new Date().getTime();
}
First the xpath of the element is fetched.
The hashcode of the xpath is then computed. We therefore have a unique id per xpath.
The problem here is that xpath are not necesseraly unique if unique elements are generated on the fly. Thus we add the timestamp at the end.
Maybe we could also garantee more unique elements by adding a final Math.Random().
You could take advantage of closure.
var i = 0;
function generateId() {
return i++;
}
If you want to enclose it:
function generator() {
var i = 0;
return function() {
return i++;
};
}
var generateId = generator();
generateId(); //1
generateId(); //2
generator could accept a default prefix; generateId coud accept an optional suffix:
function generator(prefix) {
var i = 0;
return function(suffix) {
return prefix + (i++) + (suffix || '');
};
}
var generateId = generator('_');
generateId('_'); //_1_
generateId('#'); //_2#
This comes in handy if you want your id to indicate a sequence, very much like new Date().getTime(), but easier to read.
Combining random & date in ms should do the trick with almost no change of collision :
function uniqid(){
return Math.random().toString(16).slice(2)+(new Date()).getTime()+Math.random().toString(16).slice(2);
}
alert(uniqid()+"\r"+uniqid());
const generateUniqueId = () => 'id_' + Date.now() + String(Math.random()).substr(2);
// if u want to check for collision
const arr = [];
const checkForCollision = () => {
for (let i = 0; i < 10000; i++) {
const el = generateUniqueId();
if (arr.indexOf(el) > -1) {
alert('COLLISION FOUND');
}
arr.push(el);
}
};
I think if you really want to have a unique ID then the best approach is to use a library like: uuid or uniqueid
Note: Unique ID is not the same as Random ID
To use only date time milliseconds approach is wrong.
Nowadays computers are fast enough and able to run more than one iteration of a loop in a single millisecond.
npm install uuid
Importing the library:
If you are using ES modules
import { v4 as uuidv4 } from 'uuid';
And for CommonJS:
const { v4: uuidv4 } = require('uuid');
Usage:
uuidv4();
// This will output something like: 9b1deb4d-3b7d-4bad-9bdd-2b0d7b3dcb6d
For generate unique id's:
const uid = () =>
String(
Date.now().toString(32) +
Math.random().toString(32) +
Math.random().toString(32)
).replace(/\./g, '')
For check that is works:
var size = 500000
var arr = new Array(size)
.fill(0)
.map(() => uid())
var b = new Set(arr)
console.log(
size === b.size ? 'all ids are unique' : `not unique records ${size - b.size}`
)
I managed to have a non digit unique id with this function, so i'll like to share :)
const id = btoa((Math.random(0,(new Date()).getTime())).toString()).slice(0, -10);
I sliced it for DB varchar limit reasons, but you're free to do without it.

How to get customed tags in a text, and put in another text?

The header question may not be easy to understand. Hope you can understand my detailed info below.
I have sentence data below, that has some tags, represented by [tn]tag[/tn]:
const sentence = `[t1]Sometimes[/t1] that's [t2]just the way[/t2] it has to be. Sure, there
were [t3]probably[/t3] other options, but he didn't let them [t4]enter his mind[/t4]. It
was done and that was that. It was just the way [t5]it[/t5] had to be.`
And i have parts of the sentence.
const parts = [
"Sometimes that's just the way",
"it has to be",
"Sure,",
"there were probably other options,",
"but he didn't let them enter his mind.",
"It was done and that was that.",
"It was just the way it had to be."
];
Goal is to add tags on each parts using the sentence above.
const expectedOutput = [
"[t1]Sometimes[/t1] that's [t2]just the way[/t2]",
"it has to be",
"Sure,",
"there were [t3]probably[/t3] other options,",
"but he didn't let them [t4]enter his mind[/t4].",
"It was done and that was that.",
"It was just the way [t5]it[/t5] had to be."
];
What I've tried so far are the following, but seemingly does not make sense, and I endup nothing.
make a clone sentence, and remove all tags. (code below)
find all parts in the sentence.
[problem is I don't know how to put again the tags]
I wanna ask is there any chance to achieve it? and how. thanks
export const removeTags = (content) => {
content = content.replace(/([t]|[\/t])/g, '');
return content.replace(/([t\d+]|[\/t\d+])/g, '');
};
For a regex answer: /\[t\d+\]([^[]*)\[\/t\d+\]/g will match all words including tags and then group all the words within those tags.
let regex = /\[t\d+\]([^[]*)\[\/t\d+\]/g;
let matches = [], tags = [];
var match = regex.exec(sentence);
while (match != null) {
tags.push(match[0]);
matches.push(match[1]);
match = regex.exec(sentence);
}
now we just need to replace all matches with tags inside of parts
let lastSeen = 0;
for (let i = 0; i < parts.length; i++) {
for (let j = lastSeen; j < matches.length; j++) {
if (parts[i].includes(matches[j])) {
lastSeen++;
parts[i] = parts[i].replaceAll(matches[j], tags[j])
} else if (j > lastSeen) {
break;
}
}
}
Here is a link to see the regex: regex101
And here is a JSFiddle to see the whole thing JSFiddle
Here I also made an alternative version, so just gonna dump it below. No nesting as in #thchp but a bit more easy to read imo.
const sentence = "[t1]Sometimes[/t1] that's [t2]just the way[/t2] it has to be. Sure, there" +
"were [t3]probably[/t3] other options, but he didn't let them [t4]enter his mind[/t4]. It " +
"was done and that was that. It was just the way [t5]it[/t5] had to be.";
const parts = [
"Sometimes that's just the way",
"it has to be",
"Sure,",
"there were probably other options,",
"but he didn't let them enter his mind.",
"It was done and that was that.",
"It was just the way it had to be."
];
const getTokens = (text) => {
const tokens = text.match(/\[t[0-9]+\]/gm);
const result = [];
tokens.forEach(tokenOpen => {
const tokenClose = "[/" + tokenOpen.substring(1, tokenOpen.length);
const tokenStart = text.indexOf(tokenOpen) + tokenOpen.length;
const tokenEnd = text.indexOf(tokenClose);
result.push({
tokenOpen,
tokenClose,
value: text.substr(tokenStart, tokenEnd - tokenStart)
});
});
return result;
}
const applyTokens = (parts, tokens) => {
return parts.map(part => {
const match = tokens.filter(x => part.includes(x.value));
if(!match.length)
return part;
const {value, tokenOpen, tokenClose} = match[0];
const index = part.indexOf(value);
const partPre = part.substr(0, index);
const partPost = part.substr(index + value.length, part.length);
return partPre + tokenOpen + part.substr(index, value.length) + tokenClose + partPost;
});
}
const output = applyTokens(parts, getTokens(sentence));
console.log(output);
It appends tags to all occurrences of some value in a part so the first "it" in second element of "parts" array gets wrapped as well. If you don't want that then remove once used token in "applyTokens".
Here is a solution that assumes that there are no nested tags, that all tags open and close in the part. Also, this assumes that all characters from the sentence are in parts. For this last assumption, I had to add the . after it has to be in the second expected part. I also had to remove newline characters from the sentence but I think it was because of the copy/paste.
This solution will loop through all characters and store two parallel buffers : one with the tags, one without. We will use the second one to compare with the parts, and use the first one to generate the output.
const sentence = `[t1]Sometimes[/t1] that's [t2]just the way[/t2] it has to be. Sure, there were [t3]probably[/t3] other options, but he didn't let them [t4]enter his mind[/t4]. It was done and that was that. It was just the way [t5]it[/t5] had to be.`
const parts = [
"Sometimes that's just the way",
"it has to be.",
"Sure,",
"there were probably other options,",
"but he didn't let them enter his mind.",
"It was done and that was that.",
"It was just the way it had to be."
];
let bufferWithoutTags = ""
let bufferWithTags = ""
const output = []
const buffers = []
let tagOpened = false
for (let i = 0; i < sentence.length; ++i) {
let c = sentence[i]
bufferWithTags += c
if ( c === '[') {
if (tagOpened && sentence[i+1] === "/") {
tagOpened = false
} else {
tagOpened = true
}
while (c != ']') {
c = sentence[++i]
bufferWithTags += c
}
} else {
bufferWithoutTags += c;
}
if (!tagOpened) {
for (const part of parts) {
if (part === bufferWithoutTags.trim()) {
output.push(bufferWithTags.trim())
bufferWithTags = bufferWithoutTags = ""
}
}
}
}
console.log(output)

Using querySelector to get each letter a user inputs

Trying to make a web page that will get each letter a user inputs and output it in a phonetic alphabet. For example (user types: Hello)(Output: Hotel , Echo , Lima, Lima, Oscar). This is what I have so far just need some guidance on how to get the value of each letter and compare it to like an Array to get the output.
//define UI variables
const userInput = document.querySelector('#input');
const phoneticAlphabet = ["Alpha"," Bravo","Charlie"];
//load all event listeners
loadEventListeners();
function loadEventListeners() {
//add submit event
form.addEventListener('submit', submitInput);
}
//submit user input
function submitInput(e) {
console.log(userInput.value);
if (userInput.value === '') {
alert('Add Input');
}
e.preventDefault();
}
I presume that you would like to replace non-convertible characters from the input. For the same, I am using regular expression. I have also added the response in a "p" tag. And the code runs on clicking "Submit".
Update:
Extended my array for all alphabets :)
Update 2:
Thanks #CharlieBatista for pointing out. Now, the input accepts uppercase characters as well.
//define UI variables
const form = document.phoneticForm;
const userInput = document.querySelector('#input');
const output = document.querySelector('#output');
const phoneticAlphabet = ['Alpha','Bravo','Charlie','Delta','Echo','Foxtrot','Golf','Hotel','India','Juliet','Kilo','Lima','Mike','November','Oscar','Papa','Quebec','Romeo','Sierra','Tango','Uniform','Victor','Whiskey','X-ray','Yankee','Zulu'];
//load all event listeners
loadEventListeners();
function loadEventListeners() {
//add submit event
form.addEventListener('submit', submitInput);
}
//submit user input
function submitInput(e) {
e.preventDefault();
var value = userInput.value;
if (value === '') {
alert('Add Input');
} else {
value = value.replace(/[^a-zA-Z]/gi,'');
userInput.value = value;
value = value.toLowerCase();
var outputArr = [];
for(var i = 0; i < value.length; i++){
outputArr.push(phoneticAlphabet[value.charCodeAt(i)-97]);
}
output.innerHTML = outputArr.join(', ');
}
}
<form name="phoneticForm">
<input type="text" id="input">
<input type="submit">
</form>
<p id="output"></p>
You can use the key property on the keydown event of the field to get the character that was pressed.
Then check if the key is a printable key using key.length === 1 (see this answer).
If the key is printable, convert it to uppercase, then to its character code using String.prototype.charCodeAt() and then subtract 65 from it (character A). This will give you the index in your array.
If this index is within the bounds of the array, access the array and print the character.
const phoneticAlphabet = ['Alpha','Bravo','Charlie','Delta','Echo','Foxtrot','Golf','Hotel','India','Juliet','Kilo','Lima','Mike','November','Oscar','Papa','Quebec','Romeo','Sierra','Tango','Uniform','Victor','Whiskey','X-ray','Yankee','Zulu'];
document.querySelector('#input').addEventListener('keydown', e => {
const isPrintable = e.key.length === 1;
console.clear();
if (isPrintable) {
const idx = e.key.toUpperCase().charCodeAt(0) - 65;
if (idx >= 0 && idx < phoneticAlphabet.length) {
const phoneme = phoneticAlphabet[idx];
console.log(phoneme);
}
}
});
<input type="text" id="input">

removing word from array string using .split() and .filter() methods

I am attempting to build a small app that allows the user to input a string into an array, split the string into individual array items, and then (in a separate field) input the specific word from the string desired to be filtered. The current setup enables the user to input one long string such as "this is a new string", while clicking "add string" results in the string being split ("this,is,a,new,string"). However, upon inputting one of these words into the filtering field (ex. "new"), the filter function appears to still return the enter post-split array, without filtering out the desired word. Any thoughts on how to fix this so that an inputted word chosen from the original string is filtered? Thanks!
JS:
var array = [];
function addStr() {
var str = document.getElementById("newInput").value;
var addArray = str.split(" ");
array.push(addArray);
document.getElementById("main").append(addArray);
document.getElementById("newInput").value = "";
}
function addFilterWord() {
var newText = document.getElementById("wordFilter").value;
array.push(newText);
document.getElementById("filter").append(newText);
document.getElementById("wordFilter").value = "";
const arrayUpdate = array.filter(param => {
return param != newText;
});
document.getElementById("final").append(arrayUpdate);
}
HTML:
<input id="newInput">
<button onclick="addStr()">Add String</button>
<input id="wordFilter">
<button onclick="addFilterWord()">Filter Word</button>
<p id="main"></p>
<p id="filter"></p>
<p id="final"></p>
When you push an array into an array you end up with an array with one element, which is the array you pushed. For example:
let str = "this is a new string"
let array = []
var addArray = str.split(" ");
array.push(addArray);
// array has one element
console.log("length:", array.length)
console.log(array)
You can instead spread one array into the other:
let str = "this is a new string"
let array = []
var addArray = str.split(" ");
array.push(...addArray);
// now array has all the elments on the first level
console.log("length:", array.length)
console.log(array)
There are other options is the spread operator isn't possible (like with old browsers). You can use concat() but you'll then be making a new array so you'll need to change a few things.
Here is a solution
var addArray = [];
const newInput = document.getElementById("newInput");
const wordFilter = document.getElementById("wordFilter");
const filter = document.getElementById("filter");
const final = document.getElementById("final");
const main = document.getElementById("main");
function addStr() {
var str = newInput.value;
addArray = addArray.concat(str.trim().split(" "));
newInput.value = "";
main.innerText = "Main: " + addArray.join(", ");
}
function addFilterWord() {
var newText = wordFilter.value;
filter.innerText = "Filter: " + newText;
final.innerText = "Final: " + addArray.filter(item=>item.includes(newText)).join(", ");
};
<input id="newInput">
<button onclick="addStr()">Add String</button>
<input id="wordFilter">
<button onclick="addFilterWord()">Filter Word</button>
<p id="main"></p>
<p id="filter"></p>
<p id="final"></p>
replace line no. 6 with array.push(...addArray);
comment line no. 13 //array.push(newText);
and it should work as intended :)

indexOf in an array not behaving correctly

I'm attempting to use JS to check a string for the most amount of the letters and append that result to a div. It looks so far like this:
var string = "AABBCCDDEEEEEEEEEE";
var stringInput = document.getElementById("string");
function showMostChar() {
var newInput = string.split("");
var inputAsArray = Array.of(newInput);
for (i = 0; i > inputAsArray; i++) {
if ((inputAsArray.indexOf("E")) > 9 ) {
stringInput.innerHTML = "E";
}
}
}
window.onload = showMostChar;
<div id="string"></div>
In plain english, I'm looking to split a string by character, which I then use to create an array. I loop through the array and if E has more than 9 (an arbitrary value) put E into the div. before I was using array() but I remembered thats not a valid function, so I did research and found Array.of() but I'm not seeing anything appended to string div.
is Array.of() not the right way to create an array in this context? If not why?
The ideal scenario is to log the total amount of characters that appear the most, so in this instance EEEEEEEEEE. I need to somehow get the value of each character and compare it to each other, somehow...something like:
for (i = 0; i > inputAsArray; i++) {
// somehow compare values to each other? e being each instance
// so, would that be a loop within a loop?
if ((i.value()) > e ) {
stringInput.innerHTML = i;
}
}
There are few things that needs to be fixed in your code:
First of all .split() will return an array so newInput is
already an array, you don't need any transform it.
In the other hand the right method to create a new array is
Array.from(), because Array.of() takes a Number as
argument.
Second thing you don't need any loop to check for the .indexOf(), you can directly call it upon newInput array.
And it wasn't entering the if block because .indexOf() will return
the first index of E in the array, which is lower than 9, I
used 5 for testing purpose here.
This is how should be your code:
function showMostChar() {
var newInput = string.split("");
if ((newInput.indexOf("E")) > 5 ) {
stringInput.innerHTML = "E";
}
}
Demo:
var string = "AABBCCDDEEEEEEEEEE";
var stringInput = document.getElementById("string");
function showMostChar() {
var newInput = string.split("");
console.log(newInput);
if ((newInput.indexOf("E")) > 5) {
stringInput.innerHTML = "E";
}
}
window.onload = showMostChar;
<div id="string"></div>
Edit:
To get the number of occurrences of E in the array, you can use Array.filter() like this:
function getNumberOfOccurences(char) {
var newInput = string.split("");
return newInput.filter(function(c){
return c === char;
}).length;
}
console.log(getNumberOfOccurences("E"));
Demo:
var string = "AABBCCDDEEEEEEEEEE";
var stringInput = document.getElementById("string");
function getNumberOfOccurences(char) {
var newInput = string.split("");
return newInput.filter(function(c){
return c === char;
}).length;
}
console.log(getNumberOfOccurences("E"));

Categories

Resources