How do I split text by every other line? - javascript

Or in other words by every two lines? Right now i only seem to be able to split by every line.
the list would be something like this copied into the text area:
Style:
CGV7
Fabric:
95% Polyester, 5% Elastane
Source:
Imported
Guarantee:
Lifetime Warranty
this is the result I want
Style: CGV7
Fabric: 95% Polyester, 5% Elastane
Source: Imported
Guarantee: Lifetime Warranty
here is my code:
<textarea id="tables" name="" cols="78" rows="10" onchange="splitIt()">
</textarea>
function splitIt(){
var items = [];
var tablevalues = document.getElementById("tables").value;
var splitItems =tablevalues.split(/\n/);
items.push(splitItems);
console.log(items);
}

let p = text.split('\n');
let results = '';
p.forEach((x, index) => {
if (index%2 !== 0) {
results = results + x + '\n';
}
else {
results = results +x;
}
});
console.log(results);
You can achieve this by splitting the whole string on \n and then you can add it back on every odd element concat.

I hope that this is what you are looking for:
str.replace(/[\r\n]/g, " ")
.split(" ")
.filter((x) => x.trim())
.join("\n")
Updated, this might be short and cool :)
a.split(/:\n/).join(":")

Related

Can't get values past array[0] to translate properly

Okay, to start with I should mention this is a very small personal project, and I've only have a handful of coding classes several years ago now. I can figure out a lot of the (very) basics, but have a hard time troubleshooting. I'm in a little bit over my head here, and need a dumbed down solution.
I'm trying to put together a VERY simple translator that takes in a word or sentence from the user via a text input box, puts each word of the string into an array, translates each word in order, then spits out each translated word in the order it was input. For example, typing "I like cats" would output "Ich mag Katze" in German.
I've got most of it, but I CAN'T get anything but the first array element to translate. It comes out like "Ich like cats".
I've used a loop, probably because I'm an amateur and don't know another way of doing this, and I'd rather not use any libraries or anything. This is a very small project I want to have a couple of friends utilize locally; and I know there has to be some very simple code that will just take a string, put it into an array, swap one word for another word, and then output the results, but I'm damned if I can make it work.
What I currently have is the closest I've gotten, but like I said, it doesn't work. I've jerry-rigged the loop and clearly that's the totally wrong approach, but I can't see the forest for the trees. If you can help me, please make it "Javascript for Babies" picture book levels of simple, I cannot stress enough how inexperienced I am. This is just supposed to be a fun little extra thing for my D&D group.
function checkForTranslation(input, outputDiv) {
var input = document.getElementById("inputTextField").value;
var outputDiv = document.getElementById("translationOutputDiv");
input = input.toLowerCase();
//puts user input into an array and then outputs it word by word
const myArray = input.split(" "); //added .split, thank you James, still otherwise broken
let output = "";
let translation = "";
for (let i = 0; i < myArray.length; i++) {
output += myArray[i]; //up to here, this works perfectly to put each word in the string into an array
//prints all words but doesnt translate the second onwards
translation += myArray[i];
if (output == "") {
//document.getElementById("print2").innerHTML = "Translation Here";
}
else if (output == "apple") {
translation = "x-ray";
}
else if (output == "banana") {
translation = "yak";
}
else {
translation = "???";
}
output += " "; //adds a space when displaying original user input
} // END FOR LOOP
document.getElementById("print").innerHTML = output; //this outputs the original user input to the screen
document.getElementById("print3").innerHTML = translation; //this should output the translated output to the screen
} // END FUNCTION CHECKFORTRANSLATION
What it looks like
P.S. I'm not worried about Best Practices here, this is supposed to be a quickie project that I can send to a couple friends and they can open the HTML doc, saved locally, in their browser when they want to mess around with it if they want their half-orc character to say "die by my hammer!" or something. If you have suggestions for making it neater great, but I'm not worried about a mess, no one is going to be reading this but me, and hopefully once it's fixed I'll never have to read it again either!
Since it is a manual simple translation, you should just create a "dictionary" and use it to get the translations.
var dictionary = {
"apple": "x-ray",
"banana": "yak"
}
function checkForTranslation() {
var input = document.getElementById("inputTextField").value.toLowerCase();
var words = input
.split(' ') // split string to words
.filter(function(word) { // remove empty words
return word.length > 0
});
var translatedWords = words.map(function(word) {
var wordTranslation = dictionary[word]; // get from dictionary
if (wordTranslation) {
return wordTranslation;
} else { // if word was not found in dictionary
return "???";
}
});
var translatedText = translatedWords.join(' ');
document.getElementById("translationOutputDiv").innerHTML = translatedText;
}
document.getElementById('translate').addEventListener('click', function() {
checkForTranslation();
});
<input type="text" id="inputTextField" />
<button id="translate">translate</button>
<br/>
<hr />
<div id="translationOutputDiv"></div>
Or if you want it a little more organized, you could use
const dictionary = {
"apple": "x-ray",
"banana": "yak"
}
function getTranslation(string) {
return string
.toLowerCase()
.split(' ')
.filter(word => word)
.map(word => dictionary[word] || '???')
.join(' ');
}
function translate(inputEl, outputEl) {
outputEl.innerHTML = getTranslation(inputEl.value);
}
document.querySelector('#translate').addEventListener('click', function() {
const input = document.querySelector('#inputTextField');
const output = document.querySelector('#translationOutputDiv');
translate(input, output);
});
<input type="text" id="inputTextField" />
<button id="translate">translate</button>
<br/>
<hr />
<div id="translationOutputDiv"></div>

Get initials and full last name from a string containing names

Assume there are some strings containing names in different format (each line is a possible user input):
'Guilcher, G.M., Harvey, M. & Hand, J.P.'
'Ri Liesner, Peter Tom Collins, Michael Richards'
'Manco-Johnson M, Santagostino E, Ljung R.'
I need to transform those names to get the format Lastname ABC. So each surename should be transformed to its initial which are appended to the lastname.
The example should result in
Guilcher GM, Harvey M, Hand JP
Liesner R, Collins PT, Richards M
Manco-Johnson M, Santagostino E, Ljung R
The problem is the different (possible) input format. I think my attempts are not very smart, so I'm asking for
Some hints to optimize the transformation code
How do I put those in a single function at all? I think first of all I have to test which format the string has...??
So let me explain how far I tried to solve that:
First example string
In the first example there are initials followed by a dot. The dots should be removed and the comma between the name and the initals should be removed.
firstString
.replace('.', '')
.replace(' &', ', ')
I think I do need an regex to get the comma after the name and before the initials.
Second example string
In the second example the name should be splitted by space and the last element is handled as lastname:
const elm = secondString.split(/\s+/)
const lastname = elm[elm.length - 1]
const initials = elm.map((n,i) => {
if (i !== elm.length - 1) return capitalizeFirstLetter(n)
})
return lastname + ' ' + initals.join('')
...not very elegant
Third example string
The third example has the already the correct format - only the dot at the end has to be removed. So nothing else has to be done with that input.
It wouldn't be possible without calling multiple replace() methods. The steps in provided solution is as following:
Remove all dots in abbreviated names
Substitute lastname with firstname
Replace lastnames with their beginning letter
Remove unwanted characters
Demo:
var s = `Guilcher, G.M., Harvey, M. & Hand, J.P.
Ri Liesner, Peter Tom Collins, Michael Richards
Manco-Johnson M, Santagostino E, Ljung R.`
// Remove all dots in abbreviated names
var b = s.replace(/\b([A-Z])\./g, '$1')
// Substitute first names and lastnames
.replace(/([A-Z][\w-]+(?: +[A-Z][\w-]+)*) +([A-Z][\w-]+)\b/g, ($0, $1, $2) => {
// Replace full lastnames with their first letter
return $2 + " " + $1.replace(/\b([A-Z])\w+ */g, '$1');
})
// Remove unwanted preceding / following commas and ampersands
.replace(/(,) +([A-Z]+)\b *[,&]?/g, ' $2$1');
console.log(b);
Given your example data i would try to make guesses based on name part count = 2, since it is very hard to rely on any ,, & or \n - which means treat them all as ,.
Try this against your data and let me know of any use-cases where this fails because i am highly confident that this script will fail at some point with more data :)
let testString = "Guilcher, G.M., Harvey, M. & Hand, J.P.\nRi Liesner, Peter Tom Collins, Michael Richards\nManco-Johnson M, Santagostino E, Ljung R.";
const inputToArray = i => i
.replace(/\./g, "")
.replace(/[\n&]/g, ",")
.replace(/ ?, ?/g, ",")
.split(',');
const reducer = function(accumulator, value, index, array) {
let pos = accumulator.length - 1;
let names = value.split(' ');
if(names.length > 1) {
accumulator.push(names);
} else {
if(accumulator[pos].length > 1) accumulator[++pos] = [];
accumulator[pos].push(value);
}
return accumulator.filter(n => n.length > 0);
};
console.log(inputToArray(testString).reduce(reducer, [[]]));
Here's my approach. I tried to keep it short but complexity was surprisingly high to get the edge cases.
First I'm formatting the input, to replace & for ,, and removing ..
Then, I'm splitting the input by \n, then , and finally (spaces).
Next I'm processing the chunks. On each new segment (delimited by ,), I process the previous segment. I do this because I need to be sure that the current segment isn't an initial. If that's the case, I do my best to skip that inital-only segment and process the previous one. The previous one will have the correct initial and surname, as I have all the information I neeed.
I get the initial on the segment if there's one. This will be used on the start of the next segment to process the current one.
After finishing each line, I process again the last segment, as it wont be called otherwise.
I understand the complexity is high without using regexp, and probably would have been better to use a state machine to parse the input instead.
const isInitial = s => [...s].every(c => c === c.toUpperCase());
const generateInitial = arr => arr.reduce((a, c, i) => a + (i < arr.length - 1 ? c[0].toUpperCase() : ''), '');
const formatSegment = (words, initial) => {
if (!initial) {
initial = generateInitial(words);
}
const surname = words[words.length - 1];
return {initial, surname};
}
const doDisplay = x => x.map(x => x.surname + ' ' + x.initial).join(', ');
const doProcess = _ => {
const formatted = input.value.replace(/\./g, '').replace(/&/g, ',');
const chunks = formatted.split('\n').map(x => x.split(',').map(x => x.trim().split(' ')));
const peoples = [];
chunks.forEach(line => {
let lastSegment = null;
let lastInitial = null;
let lastInitialOnly = false;
line.forEach(segment => {
if (lastSegment) {
// if segment only contains an initial, it's the initial corresponding
// to the previous segment
const initialOnly = segment.length === 1 && isInitial(segment[0]);
if (initialOnly) {
lastInitial = segment[0];
}
// avoid processing last segments that were only initials
// this prevents adding a segment twice
if (!lastInitialOnly) {
// if segment isn't an initial, we need to generate an initial
// for the previous segment, if it doesn't already have one
const people = formatSegment(lastSegment, lastInitial);
peoples.push(people);
}
lastInitialOnly = initialOnly;
// Skip initial only segments
if (initialOnly) {
return;
}
}
lastInitial = null;
// Remove the initial from the words
// to avoid getting the initial calculated for the initial
segment = segment.filter(word => {
if (isInitial(word)) {
lastInitial = word;
return false;
}
return true;
});
lastSegment = segment;
});
// Process last segment
if (!lastInitialOnly) {
const people = formatSegment(lastSegment, lastInitial);
peoples.push(people);
}
});
return peoples;
}
process.addEventListener('click', _ => {
const peoples = doProcess();
const display = doDisplay(peoples);
output.value = display;
});
.row {
display: flex;
}
.row > * {
flex: 1 0;
}
<div class="row">
<h3>Input</h3>
<h3>Output</h3>
</div>
<div class="row">
<textarea id="input" rows="10">Guilcher, G.M., Harvey, M. & Hand, J.P.
Ri Liesner, Peter Tom Collins, Michael Richards
Manco-Johnson M, Santagostino E, Ljung R.
Jordan M, Michael Jackson & Willis B.</textarea>
<textarea id="output" rows="10"></textarea>
</div>
<button id="process" style="display: block;">Process</button>

How to create ordered list inside text area using javascript?

I have a text area where I add the number of orderlist item on click of a button.This is my code,
var addListItem = function() {
if (!this.addListItem.num) {
this.addListItem.num = 0
}
++this.addListItem.num;
var text = document.getElementById('editor').value;
console.log('text', text);
var exp = '\n' + this.addListItem.num + '.\xa0';
text = text.concat(exp);
document.getElementById('editor').value = text;
}
<div>
<button onclick="addListItem()">NumberList</button>
<textarea id="editor" col=10 rows=10></textarea>
</div>
As I have used a static variable to increment it increments on every click and so if I delete the list and create a new list again it doesn't starts from '1' and also I couldn't figure out how to update the numbers when a item is added in between.Could anyone suggest me how to fix this?
If you want a more robust solution that handles all sorts of different cases, you can use regular expressions to detect what number you're at in your list.
This solution also allows users to type in their own numbers and the button click WILL STILL WORK!
That's because this solution uses the text area content as the source of truth and doesn't track state on the side.
var addListItem = function() {
var text = document.getElementById('editor').value;
// regex to match against any new line that has a number and a period
// and extracts the number. feel free to use regex101.com to understand
// this in more depth.
var listNumberRegex = /^[0-9]+(?=\.)/gm;
var existingNums = [];
var num;
// get all the matches
while ((num = listNumberRegex.exec(text)) !== null) {
existingNums.push(num);
}
// sort the values
existingNums.sort();
// use the existing biggest number + 1 or use 1.
var addListItemNum;
if (existingNums.length > 0) {
// get last number and add 1
addListItemNum = parseInt(existingNums[existingNums.length - 1], 10) + 1;
} else {
// otherwise if there's nothing, just use 1.
addListItemNum = 1;
}
var exp = '\n' + addListItemNum + '.\xa0';
text = text.concat(exp);
document.getElementById('editor').value = text;
}
<div>
<button onclick="addListItem()">NumberList</button>
<textarea id="editor" col=10 rows=10></textarea>
</div>
understanding regular expressions is tricky, feel free to view https://regex101.com/r/gyX7oO/1 to get a better understanding of what is going on.
You can try something like this:
Logic:
On every click, get the text in textarea and split it be new line.
Now that you have line items, you need to get last sentence that starts with a numeric value. But user can enter new lines on his own to format text.
For this, loop on every line and validate it it starts with number followed by ..
If yes, use substring to fetch this number and parse it to int. If no match is found, you can return 0.
This will ensure the numbering system and you do not need a variable to hold last value.
Note: This logic assumes that last value will be the maximum. If you wish to handle that, you can just compare n and parseInt and assign maximum value
Sample:
var addListItem = function() {
var text = document.getElementById('editor').value;
var exp = '\n' + (getLastNumber(text) + 1) + '.\xa0';
text = text.concat(exp);
document.getElementById('editor').value = text;
}
function getLastNumber(str){
var list = str.split(/[\r\n]/g);
var n = 0;
list.forEach(function(s){
if(/^\d+\./.test(s)){
n = parseInt(s.substring(0, s.indexOf(".")));
}
});
return n;
}
<div>
<button onclick="addListItem()">NumberList</button>
<textarea id="editor" col=10 rows=10></textarea>
</div>
If you delete the list and create a new list again it will start from '1'.
also, counts from whatever the last number is.
var addListItem = function() {
if (!this.addListItem.num) {
this.addListItem.num = 0
}
++this.addListItem.num;
var text = document.getElementById('editor').value;
//HERE start new counting if textarea is empty
if(text.trim() == ''){
this.addListItem.num = 1; //restart counting here
}
//else check if textarea has previous numbers to proceed counting
else {
var lastLine = text.substr(text.lastIndexOf("\n") + 1).trim();
this.addListItem.num = parseInt(lastLine.slice(0, -1)) + 1; //add 1 to last number
}
console.log('text', text);
var exp = '\n' + this.addListItem.num + '.\xa0';
text = text.concat(exp);
document.getElementById('editor').value = text;
}
<div>
<button onclick="addListItem()">NumberList</button>
<textarea id="editor" col=10 rows=10></textarea>
</div>

add quotes to each item in a text file

I want to use this list of bad words for my input filtering. It's a plain list right now, but I need to convert it to JSON for my server to use.
I don't want to go through each line and add quotes and a ,. Is there a regex or fast way to add " ", to each line in a txt file?
Such that:
2g1c
2 girls 1 cup
acrotomophilia
alabama hot pocket
alaskan pipeline
Becomes
"2g1c",
"2 girls 1 cup",
"acrotomophilia",
"alabama hot pocket",
"alaskan pipeline",
...
Use backtick `
var txt=`2g1c
2 girls 1 cup
acrotomophilia
alabama hot pocket
alaskan pipeline`;
var arrayUntrimmed = txt.split("\n");
var array=arrayUntrimmed.map(function(a){return a.trim()});
(Note: This ECMAScript 6 feature supported from Firefox 34 and Chrome 41)
All you have to do is split the string at the new lines and drop the last item in the array (since it's empty).
var txt = '2g1c\n2 girls 1 cup\nacrotomophilia\nalabama hot pocket\nalaskan pipeline\n';
var array = txt.split('\n').slice(0, -1);
console.log(array)
You can then use Array.prototype.some as a predicate method to find out if a given string contains one or more of the blacklisted words.
var txt = '2g1c\n2 girls 1 cup\nacrotomophilia\nalabama hot pocket\nalaskan pipeline\n';
var array = txt.split('\n').slice(0, -1);
var input1 = 'not bad';
var input2 = 'An alaskan pipeline is quite creative...';
var input1HasBadWords = array.some(function (word) {
return input1.indexOf(word) > -1;
});
var input2HasBadWords = array.some(function (word) {
return input2.indexOf(word) > -1;
});
console.log('input1 is: ' + input1HasBadWords);
console.log('input2 is: ' + input2HasBadWords);
Your controller would look something like so:
const fs = require('fs');
app.post('/route', (req, res) => {
fs.readFile('/etc/hosts', 'utf8', (err, data) => {
if (err) {
res.sendStatus(500);
}
const badWords = data.split('\n').slice(0, -1);
const hasBadWords = badWords.some((word) => {
return req.body.input.indexOf(word) > -1;
});
if(hasBadWords) {
res.send('Dirty mouth? Clean it with orbit!');
} else {
res.send('You are very polite');
}
});
});
http://pastebin.com/U5phzWUM
I guess the easiest way is to use a software for this. It took me 30 sec to do this with SublimeText
http://www.sublimetext.com/docs/selection
You can use readline module. read and add quotes in each line.
readline: https://nodejs.org/api/readline.html

to apply sequential line numbering to lines in a paragraph: is it possible?

Is it possible to have jquery/javascript insert sequential line number at the start of all lines in a paragraph and, better still, to follow the sequence through to subsequent paragraphs?
I want to be able to refer students quickly to particular lines of an article (in a classroom setting). I have lots of articles to which I would like to apply this functionality, each of which has varying numbers of paragraphs.
I was hoping this might be possible, even in a responsive page, where the width of the paragraphs changes, depending on the display device, and the consequent number of lines in each paragraph becomes greater or fewer.
Thanks in advance to anyone who can help.
Here is one approach that may suit your purposes.
Get the height of a one-line paragraph, for reference.
For each paragraph, get the actual height, and infer the number of lines.
Loop through the lines and add the numbering at absolute positions.
var refHeight = $("p").eq(0).height();
$("p").eq(0).remove();
var cnt = 1;
$("p").each(function(index) {
var pos = $(this).position();
var h = $(this).height();
var lines = h / refHeight;
var lineHeight = h / lines;
for (var i=pos.top ; i<pos.top+h ; i += lineHeight) {
var num = $("<p>", { class: "number" });
num.text(cnt++);
num.css("top", i);
$(this).before(num);
console.log(i);
}
});
(Fiddle)
Edit
If you wanted to use a fixed line length (so that everyone is seeing the same numbers), you could combine the above with the following:
Break the paragraphs into lines.
Wrap each line in a span/div, and re-append.
Block the browser from text wrapping.
$("p").each(function() {
var text = $(this).text();
$(this).html("");
var i=0;
while (i<text.length) {
lineCharWidth = charWidth;
while (i+lineCharWidth < text.length && text[i+lineCharWidth] != ' ') {
lineCharWidth++;
}
var line = $("<span>", { class: "line" }).text(text.substr(i, lineCharWidth));
$(this).append(line).append("<br/>");
i += lineCharWidth;
}
});
(Fiddle)
Here's a solution that uses a function to split the paragraph text on space characters based on a pre-determined line length and then replaces the text with an <ol> comprised of <li> elements each containing one line of text:
var lineNum = 1;
function splitLines(text, lineLen) {
var words = text.split(/\s/g), line = '', lines = [];
$.each(words, function(idx) {
line += this + ' ';
if (line.length > lineLen || idx == words.length - 1) {
lines.push(line);
line = '';
lineNum += 1;
}
});
return lines;
}
$('p').each(function() {
var $p = $(this), $ol = $('<ol start="' + lineNum + '">'), lineLen = 50;
$.each(splitLines($p.text(), lineLen), function(idx) {
$ol.append('<li>' + this + '</li>');
});
$p.text('').append($ol);
});
I'm not sure about the support for the start attribute of the <ol>. It does work in Chrome. Even still, I like using the list element because it's a little more semantically meaningful, in my opinion.
Sure. Just make sure you're encoding your line returns and use it to split up the text with a simple replace.
Sample text:
The quick
brown fox
jumped over
the lazy dog
for this, the actual string would be the following:
The quick\r\nbrown fox\r\njumped over\r\nthe lazy dog
I think something like this would work (without the document.write, and there could be performance improvements):
var input = '\r\nThe quick\r\nbrown fox\r\njumped over\r\nthe lazy dog';
input = input.replace(/\r\n/g, '<div class=\'index\'></div>');
document.write(input);
var idx = 0;
$('.index').each(function(){
$(this).text(idx++);
});
If I'm not mistaken, this should write out an index number on each line. Could use some testing/debugging, though :)
For an example of how this is done, check out Github's diff pages.

Categories

Resources