Abbreviate Sentence in Javascript - javascript

I'm trying to write a function to abbreviate words in a sentence, where there are 4 or more characters in a word. So "elephant-rides are really fun!" becomes "E6t-r3s are r4y fun!".
I managed to get up to where I abbreviated all the words, but I can't figure out three things.
My code requires that the string ends with a space. How to re-organise it so it doesn't have to end with a space for it to work?
My code doesn't work properly for words that are 3 or less characters - these are not to be abbreviated (I tried an else if statement after the if statement and it confused me)
It doesn't account for commas, semi-colons or other punctuation. Is there a way to do this without stuffing the if condition with a bunch of === statements?
Edit: I would also be interested in a non RegEx answer (although the ones that have been posted have been helpful) as I'm new to programming and am still trying to figure loops out.
function abbrv(str) {
var word=""
var newStr=""
var counter= 0
var oldCounter= 0
for (var i=0; i<str.length; i+=1){
counter+= 1
word+= str[i]
if(str[i]===" "||str[i]==="-"){
newStr += word[oldCounter]+(counter-(oldCounter+3)).toString()+word[counter-2]+str[i]
oldCounter= counter
}
}
console.log(newStr)
}
abbrv("Elephant-rides are really fun ");

You could use the \b regex to match words:
function abbrWord(word) {
if (word.length <= 3) return word; // This also filters out ", " or "-"
return word[0] +
(word.length - 2) +
word[word.length - 1];
}
function abbrv(str) {
return str.split(/\b/) // Create an array of words and word boundaries
.map(abbrWord) // for each item in the array, replace with abbr.
.join(""); // join items together to form a string
}
console.log(abbrv("Elephant-rides are really fun"))
Notes:
It's nice to have your word-abbreviation and sentence-splitting logic separated. This makes it easy to change one of the two without influencing the other
With regex, there are many ways to quickly search for certain patterns of characters. Look in to match and test as well.

You could look at each character and check for a non letter and reset the counter. If a letter is found, check the count and append if the count is zero.
function abbrv(str) {
var newStr = "",
count = 0,
i;
for (i = 0; i < str.length; i++) {
if (str[i] === " " || str[i] === "-") {
if (count > 0) {
newStr += count > 3 ? count - 2 : str[i - 2];
newStr += str[i - 1];
}
newStr += str[i];
count = 0;
continue;
}
if (count === 0) {
newStr += str[i];
}
count++;
}
if (count > 0) {
newStr += count > 3 ? count - 2 : str[i - 2];
newStr += str[i - 1];
}
return newStr;
}
console.log(abbrv("Elephant-rides are really funy"));
.as-console-wrapper { max-height: 100% !important; top: 0; }
Or you could use a regular expression for replacing the words with the abbreviation.
function abbrv(str) {
return str.replace(/\w{4,}/g, function (s) {
var l = s.length;
return s[0] + (l - 2) + s[l - 1];
});
}
console.log(abbrv("Elephant-rides are really fun"));
.as-console-wrapper { max-height: 100% !important; top: 0; }

const input = 'Elephant-rides are really fun ';
const result = input.split(/\W+/).filter(x => x).map(x => x.length < 4 ? x : x[0] + (x.length - 2) + x[x.length-1]);
console.log(result);

Related

What is the fastest way to count the number of lines in a string in JavaScript?

I'm looking for the most performant way to count the number of lines in a string in JavaScript for a string of any length. I have tested three approaches, but I feel like there may be a faster way that one of you is aware of.
Method 1:
// Split the string on newlines into an array and measure the array length
return string.split(/\r|\r\n|\n/g).length;
Method 2:
// Use match instead of split
return (string.match(/\r|\r\n|\n/g) || '').length + 1;
Method 3:
// Replace all of the newlines with empty space and compare line lengths
return string.length - string.replace(/\r|\r\n|\n/g, '').length + 1;
Find the first occurrence of a possible line break character and count this character:
function countLines(string) {
let count = 1;
let chr;
let i = 0, end = string.length;
for (; i < end; ++i) {
if (string[i] == '\n' || string[i] == '\r') {
count = 2;
chr = string[i];
break;
}
}
for (++i; i < end; ++i) {
if (string[i] == chr) {
++count;
}
}
return count;
}
const linuxString = 'Some\ntext\nwith\nfive\nlines';
const windowsString = 'Some\r\ntext\r\nwith\r\nfive\r\nlines';
const classicMacString = 'Some\rtext\rwith\rfive\rlines';
console.log(countLines(linuxString));
console.log(countLines(windowsString));
console.log(countLines(classicMacString));

Why does my code not work out well replacing strings characters?

The exercise:
The goal of this exercise 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.
Examples
"din" => "((("
"recede" => "()()()"
"Success" => ")())())"
"(( #" => "))(("
My code was like that:
function duplicateEncode(word) {
let str = "";
for (let i = 0; i < word.length; i++) { //This iteration is to examine every character in the string;
for (let j = 0; j < word.length; j++) { //This iteration is to compare every character to every other inside the string, in order to check if there is any repetition
if (j === i) { //This first conditon was selected because a character is not supposed to be compared to itself
continue;
} else if (word[i] === word[j]) {
str = str + ")";
break;
} else if (j !== word.length - 1) {
continue;
} else if (j === word.length - 1) {
str = str + "(";
}
}
}
return str;
}
Does anyone can help me figure out why it doesn't work for all cases?
For example:
console.log(duplicateEncode("abc"));
It should return ((( instead of ((
But,
console.log(duplicateEncode("mulherm"));
returns exacly what it supposed to: )((((()
Apparently, whenever a string does not have a character that repeats,the function returns a string without the first element. But whenerver the string has at least one element that repeats it returns exacly what it's supposed to.
What is going on with my code?
I think the issue is that when you use your snippet below, you prevent yourself from entering the last loop.
if (j === i) {
continue;
}
The issue is present whenever a word with a non duplicated letter is last. i.e.
This works
console.log(duplicateEncode("aba")); //returns )()
This does not
console.log(duplicateEncode("aab")); //returns ))
What you could do is add a statement that when
i === word.length - 1
and no
"(" are in your
str variable, you can append another ")" to your str.
In other words, if you have found no duplicated characters after checking the before last position while iterating over your entire word, the last is guaranteed to be unique as well.
Console logs below
function duplicateEncode(word) {
let str = "";
for (let i = 0; i < word.length; i++) { //This iteration is to examine every character in the string;
for (let j = 0; j < word.length; j++) { //This iteration is to compare every character to every other inside the string, in order to check if there is any repetition
console.log(i);
console.log(j);
console.log(str);
if (j === i) { //This first conditon was selected because a character is not supposed to be compared to itself
console.log("continue")
continue;
} else if (word[i] === word[j]) {
console.log("append )")
str = str + ")";
break;
} else if (j !== word.length - 1) {
console.log("j !== length")
continue;
} else if (j === word.length - 1) {
console.log("append (")
str = str + "(";
}
}
}
return str;
}
Use a debugger to step through your code line by line. There are cases where the inner loop completes without ever meeting one of the conditions for a adding a character to the string.
Instead, use a boolean flag to denote whether the letter is duplicated, set that inside the loop (much simpler logic), then after the loop do str += (found ? ')' : '(');. This ensures you add exactly one character to the output string per iteration of the outer loop.

Remove consecutive characters from string until it doesn't have any consecutive characters

If you see two consecutive characters that are the same, you pop them from left to right, until you cannot pop any more characters. Return the resulting string.
let str = "abba"
"abba" - pop the two b's -> "aa"
"aa" - pop the two a's -> ""
return ""
Here's what i have tried so far:
function match(str){
for (let i = 0; i< str.length; i++){
if (str[i] === str[i+1]){
return str.replace(str[i], "");
}
}
};
match('abba');
But it replaces one character only.The problem is if any two consecutive characters matches it needs to remove both of those and console (Like 'abba' to 'aa'). Then it needs to go over the updated string to do the same thing again (Like 'aa' to '')and console until the return string can't be changed anymore.
Here's another solution i found:
function removeAdjacentDuplicates(str) {
let newStr = '';
for (let i = 0; i < str.length; i++) {
if (str[i] !== str[i + 1])
if (str[i - 1] !== str[i])
newStr += str[i];
}
return newStr;
};
removeAdjacentDuplicates('abba');
But this iterates one time only. I need this to go on until there's no more consecutive characters. Also It would be great if good time complexity is maintained.
You can use a while loop to continuously loop until the result is equal to the previous result.
function removeAdjacentDuplicates(str) {
let newStr = '';
for (let i = 0; i < str.length; i++) {
if (str[i] !== str[i + 1])
if (str[i - 1] !== str[i])
newStr += str[i];
}
return newStr;
};
let before = 'abba';
let result = removeAdjacentDuplicates(before);
while(result != before){
before = result;
result = removeAdjacentDuplicates(before);
}
console.log(result);
If you want to add a limit to the number of pops, you can store the maximum pops in a variable and the number of pops in another (incremented in the loop), then add an expression to the while loop that instructs it not to execute when the number of pops is no longer smaller than the maximum number of pops permitted.
E.g:
function removeAdjacentDuplicates(str) {
let newStr = '';
for (let i = 0; i < str.length; i++) {
if (str[i] !== str[i + 1])
if (str[i - 1] !== str[i])
newStr += str[i];
}
return newStr;
};
let before = 'cabbac';
let result = removeAdjacentDuplicates(before);
const maxPop = 2;
var pops = 1; //It's 1 because we already removed the duplicates once on line 11
while (result != before && pops < maxPop) {
before = result;
result = removeAdjacentDuplicates(before);
pops++;
}
console.log(result);
You can use a regular expression to match consecutive characters and keep replacing until the string is unchanged.
function f(s) {
while (s != (s = s.replace(/(.)\1+/g, '')));
return s;
}
console.log(f("abba"))

Assistance with javascript palindrome

I am trying to solve a palindrome using a for loop in JavaScript (my code is below).
I cannot figure out what I am doing wrong. If someone can please correct and explain, it will be much appreciated. I am fairly new to coding.
var word = window.prompt("Enter a word");
function palindrome(a) {
var reversed = '';
for (i = 0; i <= a.length; i++) {
reversed = reversed + a[a.length - 1 - i];
}
if (a == reversed) {
return "true";
} else {
return "false";
}
}
document.write(palindrome(word));
On for loop inside palindrome, you have looped from 0 ~ a.length and the item on length index in a string is undefined so reversed will always be undefined.
You need to loop from 0 ~ a.length - 1 as follows.
var word = window.prompt("Enter a word");
function palindrome(a) {
var reversed = '';
for (i = 0; i < a.length; i++) {
reversed = reversed + a[a.length - 1 - i];
}
console.log(reversed);
if (a == reversed) {
return "true";
} else {
return "false";
}
}
document.write(palindrome(word));
You can reverse string simply as follows.
var word = window.prompt("Enter a word");
function palindrome(a) {
const reversed = a.split('').reverse().join('');
if (a == reversed) {
return "true";
} else {
return "false";
}
}
document.write(palindrome(word));
your loop:
for (i = 0; i <= a.length; i++) {
reversed = reversed + a[a.length - 1 - i];
}
you just need remove -1 and start the loop with 1 because when you reached the end of the iteration you will have the length of the word -1 and this will try to access a negative position.
after changing:
for (let i = 1; i <= a.length; i++) {
// you can use reversed += a[a.length - i] instead of;
reversed = reversed + a[a.length - i];
}
You can also reverse a string using the reverse method like this:
reversed = a.split('').reverse().join('');
Finally if you want to validata sentences you need to remove blank spaces and convert it in lower or upper case(usually converted in lowercase) because compare is case sensitive ("Party trap" != "part ytraP").
This code compares the first character to the last character, then advances to compare the second character to the next to last character until it runs out of characters.
As soon as it finds an inequality, it returns false because there is no reason to continue comparing.
let word = window.prompt("Enter a word");
const palindrome = a => {
let last = a.length - 1;
// loop, comparing the values until you find something that doesn't match
for (let first = 0; first <= last; first++, last--) {
if (a[first] !== a[last]) {
return "false";
}
}
// everything matched
return "true";
}
document.getElementById("output").textContent = palindrome(word);
<output id="output"></output>

Looping through a string of numbers in Javascript

Hey guys working on a problem from CoderBytes. The directions of the following:
Using the JavaScript language, have the function DashInsert(num) insert dashes ('-') between each two odd numbers in num. For example: if num is 454793 the output should be 4547-9-3. Don't count zero as an odd number.
Use the Parameter Testing feature in the box below to test your code with different arguments.
So I didn't create a function but here is my road map.
num = 3333333333
arr = num.toString().split("")
for(var i = 0; i < arr.length; i++){
if(arr[i] % 2 === 1 && arr[i + 1] % 2 === 1){
num.toString().replace(arr[i].toString() + arr[i+1].toString(),
arr[i].toString() + "-" + arr[i+1].toString())
}
}
The thing is when I run this it only puts a dash between the first two threes. I really can't figure out why this is happening. Anyone know where I am going wrong?
Here, this simple solution should do well:
var num = 3434333333
var arr = num.toString().split("");
var finalStr = "";
for(var i = 0; i < arr.length; i++){
if(arr[i] % 2 === 1 && arr[i + 1] % 2 === 1){
finalStr += arr[i] + "-";
}
else {
finalStr += arr[i];
}
}
simply keep a string for the result, if two consecutive numbers are odd append an extra "-" after the number in the string, otherwise simply append the number and your final string will contain the desired result.
See the DEMO here

Categories

Resources