Truncate characters in each word on php - javascript

I need to have no more than 25 characters in each word. Yes, I could use break-word:break-all, however, I don't like how it all works against long words.
I wrote a JavaScript function that truncates these words by letter and adds a separator. Could you suggest a better option or rewrite this program in php, since I don't know php very well yet
if(document.getElementById('title_parent') && document.getElementById('title')) {
document.getElementById('title').oninput = function() {
const parent = document.getElementsByClassName('edit-project-title')[0];
parent.innerHTML = this.value ? truncate(this.value,20,'...') : " ";
}
}
function truncate(str,maxWordLength,endLetters) {
if ("string" !== typeof str) {
return '';
}
const words = str.split(/\s+/g);
const completedWords = [];
for (let word of words) {
if (word.length > maxWordLength)
completedWords.push(word.slice(0,maxWordLength+1) + endLetters);
else
completedWords.push(word);
}
return completedWords.join(' ').replace(/\</g, "<");
}

Try this for a PHP rewrite of your JavaScript function. See comments for step-by-step explanation.
Outputs: here are some short words and a <really long one> now: pneumonoultramicrosco...
<?php
// Set some default values for max word length and end letters arguments.
// If you pass these, your paremeter values will be used.
function truncate(string $input, int $maxWordLength = 20, string $endLetters = '...')
{
// No manual type checking required if you use declare(strict_types=1),
// in combination with type hinting in the argument list.
// foreach() replaces for ... of
// preg_split() replaces String.prototype.split()
foreach (preg_split('/\s+/', $input) as $word)
{
// strlen() replaces .length
if (strlen($word) > $maxWordLength)
// substr() replaces String.prototype.slice()
$completedWords[] = substr($word, 0, $maxWordLength + 1) . $endLetters;
else
$completedWords[] = $word;
}
// implode() replaces .join()
// str_replace() replaces .replace()
return str_replace('<', '<', implode(' ', $completedWords));
}
$input = 'here are some short words and a <really long one> now: pneumonoultramicroscopicsilicovolcanoconiosis';
echo truncate($input);

Related

How to convert string to camelCase without using RegEX

I'm trying to do a challenge which is converting all strings into camelCase but without using regex, only using the methods like(split, slice, replace, includes.. etc). Some words have spaces and should remove them. Here's the CODE and I'm really STUCK. NOTE: the user enters the STRING and when user clicks the button should return to the camelCase.
INPUT =>
//underscore_case
//first_name
//Some_Variable
// calculate_AGE
//delayed_departure
OUTPUT =>
//underscoreCase
//firstName
//someVariable
//calculateAge
//delayedDeparture
document.body.append(document.createElement('textarea'));
document.body.append(document.createElement('button'));
document.querySelector('button').addEventListener('click', function() {
const text = document.querySelector('textarea').value;
const row = text.split('\n');
let [...n] = '';
for (const theText of row) {
const lowerText = theText.toLowerCase().trim();
if (lowerText.includes('_')) {
n = lowerText.replace('_', ' ');
console.log([...n]);
}
}
});
Explanation of this simple algorithm:
Your input must have words that split by a certain character, as you need something to identify which part of the string is a word. Let's assume your string has words separated by '//' instead of spaces as you mentioned in the comments, and each of those words is split by '_'.
First you need to split all words in the string into an array, you can use the split() method in order to do that.
Then when iterating through each word, split it again with split() but this time with whatever identifies the different words, in our case it's _.
Iterate through each split words, if it's the first word lowercase it using toLowerCase() and add it to the new word variable, if not, lowercase it and capitalize the first letter.
And that's it. Here's the implementation:
const inputWithoutCamelCase = 'hello_world // HOW_ARE_YOU // foo_BAR'
function stringToCamelCase(string) {
const allNames = string.split('//')
let camelCasedString = '';
for (const name of allNames) {
camelCasedString += nameToCamelCaseHelper(name);
}
return camelCasedString;
}
function nameToCamelCaseHelper(word) {
const splittedName = word.split('_');
let camelCasedName = '';
for (let i = 0; i < splittedName.length; i++) {
if (i === 0) {
camelCasedName += splittedName[i].toLowerCase();
} else {
camelCasedName += capitalizeFirstLetter(splittedName[i].toLowerCase())
}
}
return camelCasedName;
}
function capitalizeFirstLetter(string) {
return string.charAt(0).toUpperCase() + string.slice(1);
}
stringToCamelCase(inputWithoutCamelCase) // helloWorld howAreYou fooBar

How do I structure this new logic to fit into pre-existing code?

I have written a code that removes all consonants before a vowel from a string and replaces it with an 'r' and in the case, the string starts with a vowel it should return the word without doing anything to it. Now, I want to add two things I came up with to it but unfortunately, I have not been able to:
1. When the string input is all consonants then it should do nothing and just return the string.
2. If user types in space like so ' ' then it should be trimmed.
How do I place this logic in the code below without affecting what is already working?
const scoobyDoo = str => {
if(typeof str !== 'string'){
return 'This function accepts strings only';
}
let newStr = str.toLowerCase().split('');
let arrWord = newStr.length;
let regex = /[aeiou]/gi;
if (newStr[0].match(regex)){
let nothing = newStr.join('');
return nothing;
}
else {
for (let i = 0; i < arrWord; i++){
let vowelIndex = newStr.indexOf(str.match(regex)[i].toLowerCase());
newStr.splice(0, vowelIndex, 'r');
return newStr.join('');
}
}
}
console.log(scoobyDoo('scooby'));//works as expected returns 'rooby'
console.log(scoobyDoo('ethane'));//works as expected returns 'ethane'
console.log(scoobyDoo('why'));// should return 'why'
console.log(scoobyDoo(' '));// should return trimmed space and a
text telling the user only spaces were entered.
I realise this doesn't really answer your question, but your existing logic is very complicated and you could achieve the same result with String.trim, .toLowerCase and .replace:
console.log('scooby'.trim().toLowerCase().replace(/^(?=.*?[aeiou])[^aeiou]+/, 'r'))
rooby
console.log('ethane'.trim().toLowerCase().replace(/^(?=.*?[aeiou])[^aeiou]+/, 'r'))
ethane
console.log('why'.trim().toLowerCase().replace(/^(?=.*?[aeiou])[^aeiou]+/, 'r'))
why
console.log('*' + ' '.trim().toLowerCase().replace(/^(?=.*?[aeiou])[^aeiou]+/, 'r') + '*')
**
The regexp uses a positive lookahead to ensure that there is a vowel in the string, and if so replaces all leading consonants with an r.
To do something more in line with your existing function, you could try this. It still makes extensive use of regex functions though.
const scoobyDoo = str => {
if(typeof str !== 'string'){
return 'This function accepts strings only';
}
// is it a blank string?
if (str.match(/^\s+$/)) {
return '';
}
// does it start with a vowel? if so, nothing to do
if (str.match(/^[aeiou]/i)) {
return str;
}
// does it only contain consonants?
if (!str.match(/[aeiou]/i)) {
return str;
}
// must not start with a vowel but still include one
return str.replace(/^[^aeiou]+/i, 'r');
}

traversing string in javascript

I have a number of strings concatenated together
"[thing 1,thing 2,cat in the hat,Dr. Suese]"
I would like to traverse this string to stop at a specific comma (given an index) and return the substring immediately after the comma and before the next comma. The problem is I need to do it in JavaScript. I assume it would be something like this
function returnSubstring(i,theString){
var j,k = 0;
while(theString.charCodeAt(k) != ','){
while(i > 0){
if (theString.charCodeAt(j) == ','){
i--;
}
j++;
}
k++;
}
return theString.substring(j,k);
}
Is this what it should look like or is there some syntax issue here
I would like to traverse this string to stop at a specific comma (given an index) and return the substring immediately after the comma and before the next comma.
--> Let's assume specific index for comma accpeted is 8 i.e. first comma index, you can do :
var givenCommaIndex = 8;
var value = "[thing 1,thing 2,cat in the hat,Dr. Suese]";
var subString = value.substring(givenCommaIndex+1, value.indexOf(",", givenCommaIndex+1));
console.log(subString);
// Output :
"thing 2"
I can write the reusable function like below, it will not just work for comma but other delimiters as well :
function getSubString(str, delimiter, indexOfDelimiter) {
// TODO : handle specific cases like str is undefined or delimiter is null
return str.substring(indexOfDelimiter+1, str.indexOf(delimiter, indexOfDelimiter+1));
}
You may split :
var token = "[thing 1,thing 2,cat in the hat,Dr. Suese]"
.slice(1,-1) // remove [ and ]
.split(',')
[2]; // the third token
Or use a regular expression :
var token = "[thing 1,thing 2,cat in the hat,Dr. Suese]"
.match(/([^\]\[,]+)/g)
[2];

Remove all dots except the first one from a string

Given a string
'1.2.3.4.5'
I would like to get this output
'1.2345'
(In case there are no dots in the string, the string should be returned unchanged.)
I wrote this
function process( input ) {
var index = input.indexOf( '.' );
if ( index > -1 ) {
input = input.substr( 0, index + 1 ) +
input.slice( index ).replace( /\./g, '' );
}
return input;
}
Live demo: http://jsfiddle.net/EDTNK/1/
It works but I was hoping for a slightly more elegant solution...
There is a pretty short solution (assuming input is your string):
var output = input.split('.');
output = output.shift() + '.' + output.join('');
If input is "1.2.3.4", then output will be equal to "1.234".
See this jsfiddle for a proof. Of course you can enclose it in a function, if you find it necessary.
EDIT:
Taking into account your additional requirement (to not modify the output if there is no dot found), the solution could look like this:
var output = input.split('.');
output = output.shift() + (output.length ? '.' + output.join('') : '');
which will leave eg. "1234" (no dot found) unchanged. See this jsfiddle for updated code.
It would be a lot easier with reg exp if browsers supported look behinds.
One way with a regular expression:
function process( str ) {
return str.replace( /^([^.]*\.)(.*)$/, function ( a, b, c ) {
return b + c.replace( /\./g, '' );
});
}
You can try something like this:
str = str.replace(/\./,"#").replace(/\./g,"").replace(/#/,".");
But you have to be sure that the character # is not used in the string; or replace it accordingly.
Or this, without the above limitation:
str = str.replace(/^(.*?\.)(.*)$/, function($0, $1, $2) {
return $1 + $2.replace(/\./g,"");
});
You could also do something like this, i also don't know if this is "simpler", but it uses just indexOf, replace and substr.
var str = "7.8.9.2.3";
var strBak = str;
var firstDot = str.indexOf(".");
str = str.replace(/\./g,"");
str = str.substr(0,firstDot)+"."+str.substr(1,str.length-1);
document.write(str);
Shai.
Here is another approach:
function process(input) {
var n = 0;
return input.replace(/\./g, function() { return n++ > 0 ? '' : '.'; });
}
But one could say that this is based on side effects and therefore not really elegant.
This isn't necessarily more elegant, but it's another way to skin the cat:
var process = function (input) {
var output = input;
if (typeof input === 'string' && input !== '') {
input = input.split('.');
if (input.length > 1) {
output = [input.shift(), input.join('')].join('.');
}
}
return output;
};
Not sure what is supposed to happen if "." is the first character, I'd check for -1 in indexOf, also if you use substr once might as well use it twice.
if ( index != -1 ) {
input = input.substr( 0, index + 1 ) + input.substr(index + 1).replace( /\./g, '' );
}
var i = s.indexOf(".");
var result = s.substr(0, i+1) + s.substr(i+1).replace(/\./g, "");
Somewhat tricky. Works using the fact that indexOf returns -1 if the item is not found.
Trying to keep this as short and readable as possible, you can do the following:
JavaScript
var match = string.match(/^[^.]*\.|[^.]+/g);
string = match ? match.join('') : string;
Requires a second line of code, because if match() returns null, we'll get an exception trying to call join() on null. (Improvements welcome.)
Objective-J / Cappuccino (superset of JavaScript)
string = [string.match(/^[^.]*\.|[^.]+/g) componentsJoinedByString:''] || string;
Can do it in a single line, because its selectors (such as componentsJoinedByString:) simply return null when sent to a null value, rather than throwing an exception.
As for the regular expression, I'm matching all substrings consisting of either (a) the start of the string + any potential number of non-dot characters + a dot, or (b) any existing number of non-dot characters. When we join all matches back together, we have essentially removed any dot except the first.
var input = '14.1.2';
reversed = input.split("").reverse().join("");
reversed = reversed.replace(\.(?=.*\.), '' );
input = reversed.split("").reverse().join("");
Based on #Tadek's answer above. This function takes other locales into consideration.
For example, some locales will use a comma for the decimal separator and a period for the thousand separator (e.g. -451.161,432e-12).
First we convert anything other than 1) numbers; 2) negative sign; 3) exponent sign into a period ("-451.161.432e-12").
Next we split by period (["-451", "161", "432e-12"]) and pop out the right-most value ("432e-12"), then join with the rest ("-451161.432e-12")
(Note that I'm tossing out the thousand separators, but those could easily be added in the join step (.join(','))
var ensureDecimalSeparatorIsPeriod = function (value) {
var numericString = value.toString();
var splitByDecimal = numericString.replace(/[^\d.e-]/g, '.').split('.');
if (splitByDecimal.length < 2) {
return numericString;
}
var rightOfDecimalPlace = splitByDecimal.pop();
return splitByDecimal.join('') + '.' + rightOfDecimalPlace;
};
let str = "12.1223....1322311..";
let finStr = str.replace(/(\d*.)(.*)/, '$1') + str.replace(/(\d*.)(.*)/, '$2').replace(/\./g,'');
console.log(finStr)
const [integer, ...decimals] = '233.423.3.32.23.244.14...23'.split('.');
const result = [integer, decimals.join('')].join('.')
Same solution offered but using the spread operator.
It's a matter of opinion but I think it improves readability.

Get everything after the dash in a string in JavaScript

What would be the cleanest way of doing this that would work in both IE and Firefox?
My string looks like this sometext-20202
Now the sometext and the integer after the dash can be of varying length.
Should I just use substring and index of or are there other ways?
How I would do this:
// function you can use:
function getSecondPart(str) {
return str.split('-')[1];
}
// use the function:
alert(getSecondPart("sometext-20202"));
A solution I prefer would be:
const str = 'sometext-20202';
const slug = str.split('-').pop();
Where slug would be your result
var testStr = "sometext-20202"
var splitStr = testStr.substring(testStr.indexOf('-') + 1);
var the_string = "sometext-20202";
var parts = the_string.split('-', 2);
// After calling split(), 'parts' is an array with two elements:
// parts[0] is 'sometext'
// parts[1] is '20202'
var the_text = parts[0];
var the_num = parts[1];
With built-in javascript replace() function and using of regex (/(.*)-/), you can replace the substring before the dash character with empty string (""):
"sometext-20202".replace(/(.*)-/,""); // result --> "20202"
AFAIK, both substring() and indexOf() are supported by both Mozilla and IE. However, note that substr() might not be supported on earlier versions of some browsers (esp. Netscape/Opera).
Your post indicates that you already know how to do it using substring() and indexOf(), so I'm not posting a code sample.
myString.split('-').splice(1).join('-')
I came to this question because I needed what OP was asking but more than what other answers offered (they're technically correct, but too minimal for my purposes). I've made my own solution; maybe it'll help someone else.
Let's say your string is 'Version 12.34.56'. If you use '.' to split, the other answers will tend to give you '56', when maybe what you actually want is '.34.56' (i.e. everything from the first occurrence instead of the last, but OP's specific case just so happened to only have one occurrence). Perhaps you might even want 'Version 12'.
I've also written this to handle certain failures (like if null gets passed or an empty string, etc.). In those cases, the following function will return false.
Use
splitAtSearch('Version 12.34.56', '.') // Returns ['Version 12', '.34.56']
Function
/**
* Splits string based on first result in search
* #param {string} string - String to split
* #param {string} search - Characters to split at
* #return {array|false} - Strings, split at search
* False on blank string or invalid type
*/
function splitAtSearch( string, search ) {
let isValid = string !== '' // Disallow Empty
&& typeof string === 'string' // Allow strings
|| typeof string === 'number' // Allow numbers
if (!isValid) { return false } // Failed
else { string += '' } // Ensure string type
// Search
let searchIndex = string.indexOf(search)
let isBlank = (''+search) === ''
let isFound = searchIndex !== -1
let noSplit = searchIndex === 0
let parts = []
// Remains whole
if (!isFound || noSplit || isBlank) {
parts[0] = string
}
// Requires splitting
else {
parts[0] = string.substring(0, searchIndex)
parts[1] = string.substring(searchIndex)
}
return parts
}
Examples
splitAtSearch('') // false
splitAtSearch(true) // false
splitAtSearch(false) // false
splitAtSearch(null) // false
splitAtSearch(undefined) // false
splitAtSearch(NaN) // ['NaN']
splitAtSearch('foobar', 'ba') // ['foo', 'bar']
splitAtSearch('foobar', '') // ['foobar']
splitAtSearch('foobar', 'z') // ['foobar']
splitAtSearch('foobar', 'foo') // ['foobar'] not ['', 'foobar']
splitAtSearch('blah bleh bluh', 'bl') // ['blah bleh bluh']
splitAtSearch('blah bleh bluh', 'ble') // ['blah ', 'bleh bluh']
splitAtSearch('$10.99', '.') // ['$10', '.99']
splitAtSearch(3.14159, '.') // ['3', '.14159']
For those trying to get everything after the first occurrence:
Something like "Nic K Cage" to "K Cage".
You can use slice to get everything from a certain character. In this case from the first space:
const delim = " "
const name = "Nic K Cage"
const result = name.split(delim).slice(1).join(delim) // prints: "K Cage"
Or if OP's string had two hyphens:
const text = "sometext-20202-03"
// Option 1
const opt1 = text.slice(text.indexOf('-')).slice(1) // prints: 20202-03
// Option 2
const opt2 = text.split('-').slice(1).join("-") // prints: 20202-03
Efficient, compact and works in the general case:
s='sometext-20202'
s.slice(s.lastIndexOf('-')+1)
Use a regular expression of the form: \w-\d+ where a \w represents a word and \d represents a digit. They won't work out of the box, so play around. Try this.
You can use split method for it. And if you should take string from specific pattern you can use split with req. exp.:
var string = "sometext-20202";
console.log(string.split(/-(.*)/)[1])
Everyone else has posted some perfectly reasonable answers. I took a different direction. Without using split, substring, or indexOf. Works great on i.e. and firefox. Probably works on Netscape too.
Just a loop and two ifs.
function getAfterDash(str) {
var dashed = false;
var result = "";
for (var i = 0, len = str.length; i < len; i++) {
if (dashed) {
result = result + str[i];
}
if (str[i] === '-') {
dashed = true;
}
}
return result;
};
console.log(getAfterDash("adfjkl-o812347"));
My solution is performant and handles edge cases.
The point of the above code was to procrastinate work, please don't actually use it.
To use any delimiter and get first or second part
//To divide string using deimeter - here #
//str: full string that is to be splitted
//delimeter: like '-'
//part number: 0 - for string befor delimiter , 1 - string after delimiter
getPartString(str, delimter, partNumber) {
return str.split(delimter)[partNumber];
}

Categories

Resources