Duplicate Encoder (duplicate letters in a string) - javascript

The goal is to convert a string to a new string where each character in the new string is '(' if that character appears only once in the original string, or ')' if that character appears more than once in the original string. Ignore capitalization when determining if a character is a duplicate.
my problem is if it's repeating a letter first parenthese is showing wrong.
function duplicateEncode(word){
var repeat = [];
var result = [];
var letters = word.split('');
for (i=0; i < letters.length; i++){
if (repeat.indexOf(letters[i]) > -1) {
result.push(")");
} else {
result.push("(");
}
repeat.push(letters[i]);
}
return result.join("");
}
console.log(duplicateEncode("aleluia"))

"my problem is if it's repeating a letter first parenthesis is showing wrong."
This is because your code doesn't do any look-ahead, it only checks what characters have already been processed. One way or another you need to check if the current letter also appears earlier or later in the string.
The first way that came to mind was to start by counting all of the letters (putting the counts in an object), then map each letter based on its count. That way you only loop through the original word exactly twice:
function duplicateEncode(word){
var letterCount = {};
var letters = word.toLowerCase().split('');
letters.forEach(function(letter) {
letterCount[letter] = (letterCount[letter] || 0) + 1;
});
return letters.map(function(letter) {
return letterCount[letter] === 1 ? '(' : ')';
}).join('');
}
console.log(duplicateEncode("aleluia"))
console.log(duplicateEncode("AleLuia"))
console.log(duplicateEncode("No duplicates"))
console.log(duplicateEncode("All duplicated ALL DUPLICATED"))
Or the same thing with .reduce() and arrow functions is only three lines:
function duplicateEncode(word){
const letters = word.toLowerCase().split('');
const counts = letters.reduce((ct, ltr) => ((ct[ltr] = (ct[ltr] || 0) + 1), ct), {});
return letters.map(letter => counts[letter] === 1 ? '(' : ')').join('');
}
console.log(duplicateEncode("aleluia"))
console.log(duplicateEncode("AleLuia"))
console.log(duplicateEncode("No duplicates"))
console.log(duplicateEncode("All duplicated ALL DUPLICATED"))

const duplicateEncode = word => {
let newString = ''
word = word.toLowerCase() || word
word.split('').filter((x, index) => {
if(word.indexOf(x) !== index){
newString += ')'
}else if(word.lastIndexOf(x) !== index){
newString += ')'
}else{
newString += '('
}
})
return newString
}
duplicateEncode("O!!!!#k!!!H!!!)!!n!")

You can check the .length of each matched letter in string using RegExp constructor and String.prototype.match(). If .length of matched character is 1 return "(" else return ")"
const word = "aleluia";
let res = [...word].map(letter =>
word.match(new RegExp(letter, "ig")).length === 1 ? "(" : ")"
).join("");
console.log(res);

There is a more simple way to solve this task. Guess it may be more understandable for newbies in JS because the following solution contains only 4 basic level methods. So here we go.
function duplicateEncode(word) {
return word
.toLowerCase()
.split("")
.map(function (a, i, w) {
return w.indexOf(a) == w.lastIndexOf(a) ? "(" : ")";
})
.join("");
}

so:
'a' => '('
'aa' => '))'
'aba' => ')()'
'abA' => ')()'
'aba'
.toLowerCase()
.split('')
.reduce((acc, char, i, arr) => {
const symbol = arr.filter(letter => letter === char).length < 2 ? '(' : ')'
return acc + symbol
}, '')

The reason is your result array is empty until the second iteration (i = 1). The solution is to start with an array with the first element.
function duplicateEncode(word) {
var repeat = [];
var result = [];
var letters = word.split('');
for (i = 0; i < letters.length; i++) {
repeat.push(letters[0]);
if (repeat.indexOf(letters[i]) > -1) {
result.push(")");
} else {
result.push("(");
}
repeat.push(letters[i]);
}
return result.join("");
}
console.log(duplicateEncode("aleluia"))

function duplicateEncode(word){
let w = word.toLowerCase();
return Array.from(w).map(x => w.replace( new RegExp(`[^${x}]`, 'g') , "").length > 1 ? ')' : '(').join('');
}

Related

how to check first letter of every word in the string and returns next letter in the alphabet [duplicate]

I am build an autocomplete that searches off of a CouchDB View.
I need to be able to take the final character of the input string, and replace the last character with the next letter of the english alphabet. (No need for i18n here)
For Example:
Input String = "b"
startkey = "b"
endkey = "c"
OR
Input String = "foo"
startkey = "foo"
endkey = "fop"
(in case you're wondering, I'm making sure to include the option inclusive_end=false so that this extra character doesn't taint my resultset)
The Question
Is there a function natively in Javascript that can just get the next letter of the alphabet?
Or will I just need to suck it up and do my own fancy function with a base string like "abc...xyz" and indexOf()?
my_string.substring(0, my_string.length - 1)
+ String.fromCharCode(my_string.charCodeAt(my_string.length - 1) + 1)
// This will return A for Z and a for z.
function nextLetter(s){
return s.replace(/([a-zA-Z])[^a-zA-Z]*$/, function(a){
var c= a.charCodeAt(0);
switch(c){
case 90: return 'A';
case 122: return 'a';
default: return String.fromCharCode(++c);
}
});
}
A more comprehensive solution, which gets the next letter according to how MS Excel numbers it's columns... A B C ... Y Z AA AB ... AZ BA ... ZZ AAA
This works with small letters, but you can easily extend it for caps too.
getNextKey = function(key) {
if (key === 'Z' || key === 'z') {
return String.fromCharCode(key.charCodeAt() - 25) + String.fromCharCode(key.charCodeAt() - 25); // AA or aa
} else {
var lastChar = key.slice(-1);
var sub = key.slice(0, -1);
if (lastChar === 'Z' || lastChar === 'z') {
// If a string of length > 1 ends in Z/z,
// increment the string (excluding the last Z/z) recursively,
// and append A/a (depending on casing) to it
return getNextKey(sub) + String.fromCharCode(lastChar.charCodeAt() - 25);
} else {
// (take till last char) append with (increment last char)
return sub + String.fromCharCode(lastChar.charCodeAt() + 1);
}
}
return key;
};
Here is a function that does the same thing (except for upper case only, but that's easy to change) but uses slice only once and is iterative rather than recursive. In a quick benchmark, it's about 4 times faster (which is only relevant if you make really heavy use of it!).
function nextString(str) {
if (! str)
return 'A' // return 'A' if str is empty or null
let tail = ''
let i = str.length -1
let char = str[i]
// find the index of the first character from the right that is not a 'Z'
while (char === 'Z' && i > 0) {
i--
char = str[i]
tail = 'A' + tail // tail contains a string of 'A'
}
if (char === 'Z') // the string was made only of 'Z'
return 'AA' + tail
// increment the character that was not a 'Z'
return str.slice(0, i) + String.fromCharCode(char.charCodeAt(0) + 1) + tail
}
Just to explain the main part of the code that Bipul Yadav wrote (can't comment yet due to lack of reps). Without considering the loop, and just taking the char "a" as an example:
"a".charCodeAt(0) = 97...hence "a".charCodeAt(0) + 1 = 98 and String.fromCharCode(98) = "b"...so the following function for any letter will return the next letter in the alphabet:
function nextLetterInAlphabet(letter) {
if (letter == "z") {
return "a";
} else if (letter == "Z") {
return "A";
} else {
return String.fromCharCode(letter.charCodeAt(0) + 1);
}
}
var input = "Hello";
var result = ""
for(var i=0;i<input.length;i++)
{
var curr = String.fromCharCode(input.charCodeAt(i)+1);
result = result +curr;
}
console.log(result);
I understand the original question was about moving the last letter of the string forward to the next letter. But I came to this question more interested personally in changing all the letters in the string, then being able to undo that. So I took the code written by Bipul Yadav and I added some more code. The below code takes a series of letters, increments each of them to the next letter maintaining case (and enables Zz to become Aa), then rolls them back to the previous letter (and allows Aa to go back to Zz).
var inputValue = "AaZzHello";
console.log( "starting value=[" + inputValue + "]" );
var resultFromIncrementing = ""
for( var i = 0; i < inputValue.length; i++ ) {
var curr = String.fromCharCode( inputValue.charCodeAt(i) + 1 );
if( curr == "[" ) curr = "A";
if( curr == "{" ) curr = "a";
resultFromIncrementing = resultFromIncrementing + curr;
}
console.log( "resultFromIncrementing=[" + resultFromIncrementing + "]" );
inputValue = resultFromIncrementing;
var resultFromDecrementing = "";
for( var i2 = 0; i2 < inputValue.length; i2++ ) {
var curr2 = String.fromCharCode( inputValue.charCodeAt(i2) - 1 );
if( curr2 == "#" ) curr2 = "Z";
if( curr2 == "`" ) curr2 = "z";
resultFromDecrementing = resultFromDecrementing + curr2;
}
console.log( "resultFromDecrementing=[" + resultFromDecrementing + "]" );
The output of this is:
starting value=[AaZzHello]
resultFromIncrementing=[BbAaIfmmp]
resultFromDecrementing=[AaZzHello]

How to sort vowels and consonants by letter that comes out first and remove "space"

if i have "google chrome great" the output vowel is "oooeeea" and consonant is "ggglchrrt".
i try this code, but the output is "test.js:26 ooeoeea"
test("google crhome great")
function test(e){
var words = e.split("");
var vowels = "AIUEOaiueo";
var vowel = "";
for(var i = 0; i < e.length; i++){
if(vowels.includes(e[i])){
if(e[i] == 'a' || e[i] == 'A'){
vowel += e[i];
}
if(e[i] == 'i' || e[i] == 'I'){
vowel += e[i];
}
if(e[i] == 'u' || e[i] == 'U'){
vowel += e[i];
}
if(e[i] == 'e' || e[i] == 'E'){
vowel += e[i];
}
if(e[i] == 'o' || e[i] == 'O'){
vowel += e[i];
}
}
}
console.log(vowel);
}
To order the values properly, consider putting them onto an object instead, indexed by letter. On each iteration, concatenate onto (or create) the property. At the end, take the object's values.
test("google crhome great")
function test(e){
const letters = {};
for (const letter of e) {
if (/[aeiou]/i.test(letter)) {
letters[letter] = (letters[letter] || '') + letter;
}
}
const vowels = Object.values(letters).join('');
console.log(vowels);
}
This works because it'll iterate over the string to construct an object like
{
o: 'ooo',
e: 'eee',
a: 'a',
}
and then you just need to join the values together to get your string.
Use a character set in a regular expression to keep the vowel test concise.
If you need consonants too:
test("google crhome great")
function test(e){
const vs = {};
const cs = {};
for (const letter of e.replaceAll(' ', '')) {
const obj = /[aeiou]/i.test(letter) ? vs : cs;
obj[letter] = (obj[letter] || '') + letter;
}
const vowels = Object.values(vs).join('');
const consonants = Object.values(cs).join('');
console.log(vowels, consonants);
}
you can do sth like
console.log(test("google crhome great"))
function test(e){
var words = e
.toLowerCase() // for better compare and sort
.split("") // convert string to array
.filter(el => el !== " ") // remove spaces
var vowel = words
.filter(el => "aiueo" // to find vowel letters
.split("") // to create vowel letter array
.includes(el)
).sort((a,b) =>
a.localeCompare(b) // sort from a to z. you can replace a with b and b with a for reverse sorting
).join('') // to convert array to string
var consonant = words
.filter(el => !"aiueo"
.split("")
.includes(el)
).sort((a,b) =>
a.localeCompare(b)
).join('')
return {vowel, consonant}
}

Return the first non-repeating character of a string

In the first chunk of my code I have an ' if ' statement that is not working as it should, and I can't figure out why.
When using the argument 'hous', it should enter the first ' if ' statement and return 0. It returns -1 instead.
var firstUniqChar = function(s) {
for (let i = 0; i < s.length; i++){
let letter = s[i];
// console.log('s[i]: ' + letter);
// console.log(s.slice(1));
// console.log( 'i: ' + i);
if ((i = 0) && !(s.slice(1).includes(letter))) {
return 0;
}
if ((i = s.length - 1) && !(s.slice(0, i).includes(letter))) {
return 1;
}
if(!(s.slice(0, i).includes(letter)) && !(s.slice(i + 1).includes(letter))) {
return 2;
}
}
return -1;
};
console.log(firstUniqChar("hous"));
This is another way you can write your function:
const firstUniqChar = s => [...s].filter(c=>!(s.split(c).length-2))[0] || -1;
console.log(firstUniqChar("hous"));
console.log(firstUniqChar("hhoous"));
console.log(firstUniqChar("hhoouuss"));
Look up method for scattered repeated characters and functional find()-based approach
You may break your input string into array of characters (e.g. using spread syntax ...) and make use of Array.prototype.find() (to get character itserlf) or Array.prototype.findIndex() (to get non repeating character position) by finding the character that is different from its neighbors:
const src = 'hhoous',
getFirstNonRepeating = str =>
[...str].find((c,i,s) =>
(!i && c != s[i+1]) ||
(c != s[i-1] && (!s[i+1] || c != s[i+1])))
console.log(getFirstNonRepeating(src))
.as-console-wrapper{min-height:100%;}
Above will work perfectly when your repeating characters are groupped together, if not, I may recommend to do 2-passes over the array of characters - one, to count ocurrence of each character, and one more, to find out the first unique:
const src = 'hohuso',
getFirstUnique = str => {
const hashMap = [...str].reduce((r,c,i) =>
(r[c]=r[c]||{position:i, count:0}, r[c].count++, r), {})
return Object
.entries(hashMap)
.reduce((r,[char,{position,count}]) =>
((count == 1 && (!r.char || position < r.position)) &&
(r = {char, position}),
r), {})
}
console.log(getFirstUnique(src))
.as-console-wrapper{min-height:100%;}
function nonRepeat(str) {
return Array
.from(str)
.find((char) => str.match(newRegExp(char,'g')).length === 1);
}
console.log(nonRepeat('abacddbec')); // e
console.log(nonRepeat('1691992933')); // 6
console.log(nonRepeat('thhinkninw')); // t

READ TEXT FILE AND CONVERT TO JSON IN JavaScript [duplicate]

Where could I find some JavaScript code to parse CSV data?
You can use the CSVToArray() function mentioned in this blog entry.
<script type="text/javascript">
// ref: http://stackoverflow.com/a/1293163/2343
// This will parse a delimited string into an array of
// arrays. The default delimiter is the comma, but this
// can be overriden in the second argument.
function CSVToArray( strData, strDelimiter ){
// Check to see if the delimiter is defined. If not,
// then default to comma.
strDelimiter = (strDelimiter || ",");
// Create a regular expression to parse the CSV values.
var objPattern = new RegExp(
(
// Delimiters.
"(\\" + strDelimiter + "|\\r?\\n|\\r|^)" +
// Quoted fields.
"(?:\"([^\"]*(?:\"\"[^\"]*)*)\"|" +
// Standard fields.
"([^\"\\" + strDelimiter + "\\r\\n]*))"
),
"gi"
);
// Create an array to hold our data. Give the array
// a default empty first row.
var arrData = [[]];
// Create an array to hold our individual pattern
// matching groups.
var arrMatches = null;
// Keep looping over the regular expression matches
// until we can no longer find a match.
while (arrMatches = objPattern.exec( strData )){
// Get the delimiter that was found.
var strMatchedDelimiter = arrMatches[ 1 ];
// Check to see if the given delimiter has a length
// (is not the start of string) and if it matches
// field delimiter. If id does not, then we know
// that this delimiter is a row delimiter.
if (
strMatchedDelimiter.length &&
strMatchedDelimiter !== strDelimiter
){
// Since we have reached a new row of data,
// add an empty row to our data array.
arrData.push( [] );
}
var strMatchedValue;
// Now that we have our delimiter out of the way,
// let's check to see which kind of value we
// captured (quoted or unquoted).
if (arrMatches[ 2 ]){
// We found a quoted value. When we capture
// this value, unescape any double quotes.
strMatchedValue = arrMatches[ 2 ].replace(
new RegExp( "\"\"", "g" ),
"\""
);
} else {
// We found a non-quoted value.
strMatchedValue = arrMatches[ 3 ];
}
// Now that we have our value string, let's add
// it to the data array.
arrData[ arrData.length - 1 ].push( strMatchedValue );
}
// Return the parsed data.
return( arrData );
}
</script>
jQuery-CSV
It's a jQuery plugin designed to work as an end-to-end solution for parsing CSV into JavaScript data. It handles every single edge case presented in RFC 4180, as well as some that pop up for Excel/Google spreadsheet exports (i.e., mostly involving null values) that the specification is missing.
Example:
track,artist,album,year
Dangerous,'Busta Rhymes','When Disaster Strikes',1997
// Calling this
music = $.csv.toArrays(csv)
// Outputs...
[
["track", "artist", "album", "year"],
["Dangerous", "Busta Rhymes", "When Disaster Strikes", "1997"]
]
console.log(music[1][2]) // Outputs: 'When Disaster Strikes'
Update:
Oh yeah, I should also probably mention that it's completely configurable.
music = $.csv.toArrays(csv, {
delimiter: "'", // Sets a custom value delimiter character
separator: ';', // Sets a custom field separator character
});
Update 2:
It now works with jQuery on Node.js too. So you have the option of doing either client-side or server-side parsing with the same library.
Update 3:
Since the Google Code shutdown, jquery-csv has been migrated to GitHub.
Disclaimer: I am also the author of jQuery-CSV.
Here's an extremely simple CSV parser that handles quoted fields with commas, new lines, and escaped double quotation marks. There's no splitting or regular expression. It scans the input string 1-2 characters at a time and builds an array.
Test it at http://jsfiddle.net/vHKYH/.
function parseCSV(str) {
var arr = [];
var quote = false; // 'true' means we're inside a quoted field
// Iterate over each character, keep track of current row and column (of the returned array)
for (var row = 0, col = 0, c = 0; c < str.length; c++) {
var cc = str[c], nc = str[c+1]; // Current character, next character
arr[row] = arr[row] || []; // Create a new row if necessary
arr[row][col] = arr[row][col] || ''; // Create a new column (start with empty string) if necessary
// If the current character is a quotation mark, and we're inside a
// quoted field, and the next character is also a quotation mark,
// add a quotation mark to the current column and skip the next character
if (cc == '"' && quote && nc == '"') { arr[row][col] += cc; ++c; continue; }
// If it's just one quotation mark, begin/end quoted field
if (cc == '"') { quote = !quote; continue; }
// If it's a comma and we're not in a quoted field, move on to the next column
if (cc == ',' && !quote) { ++col; continue; }
// If it's a newline (CRLF) and we're not in a quoted field, skip the next character
// and move on to the next row and move to column 0 of that new row
if (cc == '\r' && nc == '\n' && !quote) { ++row; col = 0; ++c; continue; }
// If it's a newline (LF or CR) and we're not in a quoted field,
// move on to the next row and move to column 0 of that new row
if (cc == '\n' && !quote) { ++row; col = 0; continue; }
if (cc == '\r' && !quote) { ++row; col = 0; continue; }
// Otherwise, append the current character to the current column
arr[row][col] += cc;
}
return arr;
}
I have an implementation as part of a spreadsheet project.
This code is not yet tested thoroughly, but anyone is welcome to use it.
As some of the answers noted though, your implementation can be much simpler if you actually have DSV or TSV file, as they disallow the use of the record and field separators in the values. CSV, on the other hand, can actually have commas and newlines inside a field, which breaks most regular expression and split-based approaches.
var CSV = {
parse: function(csv, reviver) {
reviver = reviver || function(r, c, v) { return v; };
var chars = csv.split(''), c = 0, cc = chars.length, start, end, table = [], row;
while (c < cc) {
table.push(row = []);
while (c < cc && '\r' !== chars[c] && '\n' !== chars[c]) {
start = end = c;
if ('"' === chars[c]){
start = end = ++c;
while (c < cc) {
if ('"' === chars[c]) {
if ('"' !== chars[c+1]) {
break;
}
else {
chars[++c] = ''; // unescape ""
}
}
end = ++c;
}
if ('"' === chars[c]) {
++c;
}
while (c < cc && '\r' !== chars[c] && '\n' !== chars[c] && ',' !== chars[c]) {
++c;
}
} else {
while (c < cc && '\r' !== chars[c] && '\n' !== chars[c] && ',' !== chars[c]) {
end = ++c;
}
}
row.push(reviver(table.length-1, row.length, chars.slice(start, end).join('')));
if (',' === chars[c]) {
++c;
}
}
if ('\r' === chars[c]) {
++c;
}
if ('\n' === chars[c]) {
++c;
}
}
return table;
},
stringify: function(table, replacer) {
replacer = replacer || function(r, c, v) { return v; };
var csv = '', c, cc, r, rr = table.length, cell;
for (r = 0; r < rr; ++r) {
if (r) {
csv += '\r\n';
}
for (c = 0, cc = table[r].length; c < cc; ++c) {
if (c) {
csv += ',';
}
cell = replacer(r, c, table[r][c]);
if (/[,\r\n"]/.test(cell)) {
cell = '"' + cell.replace(/"/g, '""') + '"';
}
csv += (cell || 0 === cell) ? cell : '';
}
}
return csv;
}
};
csvToArray v1.3
A compact (645 bytes), but compliant function to convert a CSV string into a 2D array, conforming to the RFC4180 standard.
https://code.google.com/archive/p/csv-to-array/downloads
Common Usage: jQuery
$.ajax({
url: "test.csv",
dataType: 'text',
cache: false
}).done(function(csvAsString){
csvAsArray=csvAsString.csvToArray();
});
Common usage: JavaScript
csvAsArray = csvAsString.csvToArray();
Override field separator
csvAsArray = csvAsString.csvToArray("|");
Override record separator
csvAsArray = csvAsString.csvToArray("", "#");
Override Skip Header
csvAsArray = csvAsString.csvToArray("", "", 1);
Override all
csvAsArray = csvAsString.csvToArray("|", "#", 1);
Here's my PEG(.js) grammar that seems to do ok at RFC 4180 (i.e. it handles the examples at http://en.wikipedia.org/wiki/Comma-separated_values):
start
= [\n\r]* first:line rest:([\n\r]+ data:line { return data; })* [\n\r]* { rest.unshift(first); return rest; }
line
= first:field rest:("," text:field { return text; })*
& { return !!first || rest.length; } // ignore blank lines
{ rest.unshift(first); return rest; }
field
= '"' text:char* '"' { return text.join(''); }
/ text:[^\n\r,]* { return text.join(''); }
char
= '"' '"' { return '"'; }
/ [^"]
Try it out at http://jsfiddle.net/knvzk/10 or http://pegjs.majda.cz/online. Download the generated parser at https://gist.github.com/3362830.
Here's another solution. This uses:
a coarse global regular expression for splitting the CSV string (which includes surrounding quotes and trailing commas)
fine-grained regular expression for cleaning up the surrounding quotes and trailing commas
also, has type correction differentiating strings, numbers, boolean values and null values
For the following input string:
"This is\, a value",Hello,4,-123,3.1415,'This is also\, possible',true,
The code outputs:
[
"This is, a value",
"Hello",
4,
-123,
3.1415,
"This is also, possible",
true,
null
]
Here's my implementation of parseCSVLine() in a runnable code snippet:
function parseCSVLine(text) {
return text.match( /\s*(\"[^"]*\"|'[^']*'|[^,]*)\s*(,|$)/g ).map( function (text) {
let m;
if (m = text.match(/^\s*,?$/)) return null; // null value
if (m = text.match(/^\s*\"([^"]*)\"\s*,?$/)) return m[1]; // Double Quoted Text
if (m = text.match(/^\s*'([^']*)'\s*,?$/)) return m[1]; // Single Quoted Text
if (m = text.match(/^\s*(true|false)\s*,?$/)) return m[1] === "true"; // Boolean
if (m = text.match(/^\s*((?:\+|\-)?\d+)\s*,?$/)) return parseInt(m[1]); // Integer Number
if (m = text.match(/^\s*((?:\+|\-)?\d*\.\d*)\s*,?$/)) return parseFloat(m[1]); // Floating Number
if (m = text.match(/^\s*(.*?)\s*,?$/)) return m[1]; // Unquoted Text
return text;
} );
}
let data = `"This is\, a value",Hello,4,-123,3.1415,'This is also\, possible',true,`;
let obj = parseCSVLine(data);
console.log( JSON.stringify( obj, undefined, 2 ) );
Here's my simple vanilla JavaScript code:
let a = 'one,two,"three, but with a comma",four,"five, with ""quotes"" in it.."'
console.log(splitQuotes(a))
function splitQuotes(line) {
if(line.indexOf('"') < 0)
return line.split(',')
let result = [], cell = '', quote = false;
for(let i = 0; i < line.length; i++) {
char = line[i]
if(char == '"' && line[i+1] == '"') {
cell += char
i++
} else if(char == '"') {
quote = !quote;
} else if(!quote && char == ',') {
result.push(cell)
cell = ''
} else {
cell += char
}
if ( i == line.length-1 && cell) {
result.push(cell)
}
}
return result
}
I'm not sure why I couldn't get Kirtan's example to work for me. It seemed to be failing on empty fields or maybe fields with trailing commas...
This one seems to handle both.
I did not write the parser code, just a wrapper around the parser function to make this work for a file. See attribution.
var Strings = {
/**
* Wrapped CSV line parser
* #param s String delimited CSV string
* #param sep Separator override
* #attribution: http://www.greywyvern.com/?post=258 (comments closed on blog :( )
*/
parseCSV : function(s,sep) {
// http://stackoverflow.com/questions/1155678/javascript-string-newline-character
var universalNewline = /\r\n|\r|\n/g;
var a = s.split(universalNewline);
for(var i in a){
for (var f = a[i].split(sep = sep || ","), x = f.length - 1, tl; x >= 0; x--) {
if (f[x].replace(/"\s+$/, '"').charAt(f[x].length - 1) == '"') {
if ((tl = f[x].replace(/^\s+"/, '"')).length > 1 && tl.charAt(0) == '"') {
f[x] = f[x].replace(/^\s*"|"\s*$/g, '').replace(/""/g, '"');
} else if (x) {
f.splice(x - 1, 2, [f[x - 1], f[x]].join(sep));
} else f = f.shift().split(sep).concat(f);
} else f[x].replace(/""/g, '"');
} a[i] = f;
}
return a;
}
}
Regular expressions to the rescue! These few lines of code handle properly quoted fields with embedded commas, quotes, and newlines based on the RFC 4180 standard.
function parseCsv(data, fieldSep, newLine) {
fieldSep = fieldSep || ',';
newLine = newLine || '\n';
var nSep = '\x1D';
var qSep = '\x1E';
var cSep = '\x1F';
var nSepRe = new RegExp(nSep, 'g');
var qSepRe = new RegExp(qSep, 'g');
var cSepRe = new RegExp(cSep, 'g');
var fieldRe = new RegExp('(?<=(^|[' + fieldSep + '\\n]))"(|[\\s\\S]+?(?<![^"]"))"(?=($|[' + fieldSep + '\\n]))', 'g');
var grid = [];
data.replace(/\r/g, '').replace(/\n+$/, '').replace(fieldRe, function(match, p1, p2) {
return p2.replace(/\n/g, nSep).replace(/""/g, qSep).replace(/,/g, cSep);
}).split(/\n/).forEach(function(line) {
var row = line.split(fieldSep).map(function(cell) {
return cell.replace(nSepRe, newLine).replace(qSepRe, '"').replace(cSepRe, ',');
});
grid.push(row);
});
return grid;
}
const csv = 'A1,B1,C1\n"A ""2""","B, 2","C\n2"';
const separator = ','; // field separator, default: ','
const newline = ' <br /> '; // newline representation in case a field contains newlines, default: '\n'
var grid = parseCsv(csv, separator, newline);
// expected: [ [ 'A1', 'B1', 'C1' ], [ 'A "2"', 'B, 2', 'C <br /> 2' ] ]
You don't need a parser-generator such as lex/yacc. The regular expression handles RFC 4180 properly thanks to positive lookbehind, negative lookbehind, and positive lookahead.
Clone/download code at https://github.com/peterthoeny/parse-csv-js
Just throwing this out there.. I recently ran into the need to parse CSV columns with Javascript, and I opted for my own simple solution. It works for my needs, and may help someone else.
const csvString = '"Some text, some text",,"",true,false,"more text","more,text, more, text ",true';
const parseCSV = text => {
const lines = text.split('\n');
const output = [];
lines.forEach(line => {
line = line.trim();
if (line.length === 0) return;
const skipIndexes = {};
const columns = line.split(',');
output.push(columns.reduce((result, item, index) => {
if (skipIndexes[index]) return result;
if (item.startsWith('"') && !item.endsWith('"')) {
while (!columns[index + 1].endsWith('"')) {
index++;
item += `,${columns[index]}`;
skipIndexes[index] = true;
}
index++;
skipIndexes[index] = true;
item += `,${columns[index]}`;
}
result.push(item);
return result;
}, []));
});
return output;
};
console.log(parseCSV(csvString));
Personally I like to use deno std library since most modules are officially compatible with the browser
The problem is that the std is in typescript but official solution might happen in the future https://github.com/denoland/deno_std/issues/641 https://github.com/denoland/dotland/issues/1728
For now there is an actively maintained on the fly transpiler https://bundle.deno.dev/
so you can use it simply like this
<script type="module">
import { parse } from "https://bundle.deno.dev/https://deno.land/std#0.126.0/encoding/csv.ts"
console.log(await parse("a,b,c\n1,2,3"))
</script>
I have constructed this JavaScript script to parse a CSV in string to array object. I find it better to break down the whole CSV into lines, fields and process them accordingly. I think that it will make it easy for you to change the code to suit your need.
//
//
// CSV to object
//
//
const new_line_char = '\n';
const field_separator_char = ',';
function parse_csv(csv_str) {
var result = [];
let line_end_index_moved = false;
let line_start_index = 0;
let line_end_index = 0;
let csr_index = 0;
let cursor_val = csv_str[csr_index];
let found_new_line_char = get_new_line_char(csv_str);
let in_quote = false;
// Handle \r\n
if (found_new_line_char == '\r\n') {
csv_str = csv_str.split(found_new_line_char).join(new_line_char);
}
// Handle the last character is not \n
if (csv_str[csv_str.length - 1] !== new_line_char) {
csv_str += new_line_char;
}
while (csr_index < csv_str.length) {
if (cursor_val === '"') {
in_quote = !in_quote;
} else if (cursor_val === new_line_char) {
if (in_quote === false) {
if (line_end_index_moved && (line_start_index <= line_end_index)) {
result.push(parse_csv_line(csv_str.substring(line_start_index, line_end_index)));
line_start_index = csr_index + 1;
} // Else: just ignore line_end_index has not moved or line has not been sliced for parsing the line
} // Else: just ignore because we are in a quote
}
csr_index++;
cursor_val = csv_str[csr_index];
line_end_index = csr_index;
line_end_index_moved = true;
}
// Handle \r\n
if (found_new_line_char == '\r\n') {
let new_result = [];
let curr_row;
for (var i = 0; i < result.length; i++) {
curr_row = [];
for (var j = 0; j < result[i].length; j++) {
curr_row.push(result[i][j].split(new_line_char).join('\r\n'));
}
new_result.push(curr_row);
}
result = new_result;
}
return result;
}
function parse_csv_line(csv_line_str) {
var result = [];
//let field_end_index_moved = false;
let field_start_index = 0;
let field_end_index = 0;
let csr_index = 0;
let cursor_val = csv_line_str[csr_index];
let in_quote = false;
// Pretend that the last char is the separator_char to complete the loop
csv_line_str += field_separator_char;
while (csr_index < csv_line_str.length) {
if (cursor_val === '"') {
in_quote = !in_quote;
} else if (cursor_val === field_separator_char) {
if (in_quote === false) {
if (field_start_index <= field_end_index) {
result.push(parse_csv_field(csv_line_str.substring(field_start_index, field_end_index)));
field_start_index = csr_index + 1;
} // Else: just ignore field_end_index has not moved or field has not been sliced for parsing the field
} // Else: just ignore because we are in quote
}
csr_index++;
cursor_val = csv_line_str[csr_index];
field_end_index = csr_index;
field_end_index_moved = true;
}
return result;
}
function parse_csv_field(csv_field_str) {
with_quote = (csv_field_str[0] === '"');
if (with_quote) {
csv_field_str = csv_field_str.substring(1, csv_field_str.length - 1); // remove the start and end quotes
csv_field_str = csv_field_str.split('""').join('"'); // handle double quotes
}
return csv_field_str;
}
// Initial method: check the first newline character only
function get_new_line_char(csv_str) {
if (csv_str.indexOf('\r\n') > -1) {
return '\r\n';
} else {
return '\n'
}
}
Just use .split(','):
var str = "How are you doing today?";
var n = str.split(" ");

CoderByte Letter Changes Java Script

The question is :
Using the JavaScript, have the function LetterChanges(str) take the str parameter being passed and modify it using the following algorithm. Replace every letter in the string with the letter following it in the alphabet (ie. c becomes d, z becomes a). Then capitalize every vowel in this new string (a, e, i, o, u) and finally return this modified string.
function LetterChanges(str){
var result = "";
for(var i = 0; i < str.length; i++) {
var letters = str[i];
if (letters == "a"|| letters == "e"|| letters == "i"|| letters == "o"|| letters =="u") {
letters = letters.toUpperCase();
result+=letters;
} else if (letters == "z") {
letters = "a";
} else {
var answer = "";
var realanswer="";
for (var i =0;i<str.length;i++) {
answer += (String.fromCharCode(str.charCodeAt(i)+1));
}
realanswer += answer
}
}
return realanswer;
return result;
}
LetterChanges();
basically, if return realanswer is placed before return result and LetterChanges is called with "o" i get the output undefined. But if it is called with a non vowel such as "b" it will output "c" which is correct.
now if i place return result before return realanswer it will work properly for vowels but not for other letters. thanks for the help
function LetterChanges(str) {
return str
.replace(/[a-zA-Z]/g, (x) => String.fromCharCode(x.charCodeAt(0)+1))
.replace(/[aeiou]/g, (v) => v.toUpperCase());
}
The first part modifies the consonants by an increment of 1.
Regex is isolating the characters with [] versus no brackets at all. g ensures that the regex is applied anywhere in the string, as opposed to not putting g which gives you the first occurrence of the search.
You have to convert the characters in the string to their Unicode because incrementing is a math operation. x.charCodeAt(0) is saying at the index of 0 of the string in the argument. The increment of 1 is not within the parentheses but outside.
The second part modifies the vowels to upper case.
This is pretty straightforward, the regex only finds the individual characters because [] are used, g for anywhere in the string. and the modifier is to make the characters become upper case.
function LetterChanges(str) {
var lstr = "";// Took a variable to store after changing alphabet//
for(var i=0;i<str.length;i++){
var asVal = (str.charCodeAt(i)+1);// To convert string to Ascii value and 1 to it//
lstr += (String.fromCharCode(asVal));// To convert back to string from Asii value//
}
console.log("Before converting vowels :"+lstr); //Printing in console changed alphabet//
var neword =""; // variable to store word after changing vowels to uppercase//
for(i=0;i<lstr.length;i++){
var strng = lstr[i]; // Storing every letter in strng variable while running loop //
if(strng=="a"||strng=="e"||strng=="i"||strng=="o"||strng=="u"){
neword += strng.toUpperCase(); // If it a vowel it gets uppercased and added //
}
else{
neword += strng; // If not vowel , it just gets added without Uppercase //
}
}
console.log("After converting vowels :"+neword); //Printing in console the word after captilising the vowels //
}
LetterChanges("Goutham"); // Calling a function with string Goutham //
function letterChanges(str) {
let res = '';
let arr = str.toLowerCase().split('');
// Iterate through loop
for(let i = 0; i < str.length; i++) {
// Convert String into ASCII value and add 1
let temp = str.charCodeAt(i) + 1;
// Convert ASCII value back into String to the result
res += (String.fromCharCode(temp));
}
console.log(res);
// Replace only vowel characters to Uppercase using callback in the replace function
return res.replace(/[aeiou]/g, (letters) {
return letters.toUpperCase();
});
}
function LetterChanges(str) {
return str
.split('')
.map((c) => String.fromCharCode((c >= 'a' && c <= 'z') ? (c.charCodeAt(0)-97+1)%26+97 : (c >= 'A' && c <= 'Z') ? (c.charCodeAt(0)+1-65)%26+65 : c.charCodeAt(0)))
.join('').replace(/[aeiou]/g, (letters) => letters.toUpperCase());
}
export const letterChange=(str)=>{
let newStr = str.toLowerCase().replace(/[a-z]/gi, (char)=>{
if(char==="z"){
return "a"
}else{
return String.fromCharCode(char.charCodeAt()+1)
}
})
let wordCap = newStr.replace(/a|e|i|o|u/gi, char => char.toUpperCase())
return wordCap
}
function changeLetters(str) {
var result = "";
for (var i = 0; i < str.length; i++) {
var item = str[i];
if (
item == "a" ||
item == "e" ||
item == "i" ||
item == "o" ||
item == "u"
) {
item = item.toUpperCase();
result += item;
} else if (item == "z") {
letters = "a";
result += item;
} else {
result += String.fromCharCode(str.charCodeAt(i) + 1);
}
}
return result;
}

Categories

Resources