Hopefully a basic question, as I'm a bit lost where to begin.
Pretend we have this string in JS:
var foo = "Yes, today #hello #vcc #toomanyhashtags #test we went to the park and danced"
How would I go about dynamically finding the character "#" and removing everything after until it hits a space (or in the instance of #test, until the string ends)?
ie. So the above string would read:
var foo = "Yes, today we went to the park and danced "
I had the concept to loop through the entire strings' characters and if the character === "#", delete characters until the current loop's item === " ". Is there a shorter way to do this?
Preliminary Concept:
var foo = "Hello, this is my test #test #hello";
var stripHashtags = function(x) {
for (i=0; i < x.length; i++) {
if (x[i] !== "#") {
console.log(x[i]);
}
}
};
stripHashtags(foo);
You could also do it with a simple regex string
foo.replace(/#[^ ]*/g, ""))
foo.substr(0,foo.indexOf("#")). This can get you the required output i suppose if that's what you are looking for.
You could go about this using the indexOf() method available to strings. This returns the character location of the first occurrence of whatever you're looking for. Then use substring
var i = foo.indexOf('#');
foo = foo.substr(0,i);
Related
I am using extendscript to build some invoices from downloaded plaintext emails (.txt)
At points in the file there are lines of text that look like "Order Number: 123456" and then the line ends. I have a script made from parts I found on this site that finds the end of "Order Number:" in order to get a starting position of a substring. I want to use where the return key was hit to go to the next line as the second index number to finish the substring. To do this, I have another piece of script from the helpful people of this site that makes an array out of the indexes of every instance of a character. I will then use whichever array object is a higher number than the first number for the substring.
It's a bit convoluted, but I'm not great with Javascript yet, and if there is an easier way, I don't know it.
What is the character I need to use to emulate a return key in a txt file in javascript for extendscript for indesign?
Thank you.
I have tried things like \n and \r\n and ^p both with and without quotes around them but none of those seem to show up in the array when I try them.
//Load Email as String
var b = new File("~/Desktop/Test/email.txt");
b.open('r');
var str = "";
while (!b.eof)
str += b.readln();
b.close();
var orderNumberLocation = str.search("Order Number: ") + 14;
var orderNumber = str.substring(orderNumberLocation, ARRAY NUMBER GOES HERE)
var loc = orderNumberLocation.lineNumber
function indexes(source, find) {
var result = [];
for (i = 0; i < source.length; ++i) {
// If you want to search case insensitive use
// if (source.substring(i, i + find.length).toLowerCase() == find) {
if (source.substring(i, i + find.length) == find) {
result.push(i);
}
}
alert(result)
}
indexes(str, NEW PARAGRAPH CHARACTER GOES HERE)
I want all my line breaks to show up as an array of indexes in the variable "result".
Edit: My method of importing stripped all line breaks from the document. Using the code below instead works better. Now \n works.
var file = File("~/Desktop/Test/email.txt", "utf-8");
file.open("r");
var str = file.read();
file.close();
You need to use Regular Expressions. Depending on the fields do you need to search, you'l need to tweek the regular expressions, but I can give you a point. If the fields on the email are separated by new lines, something like that will work:
var str; //your string
var fields = {}
var lookFor = /(Order Number:|Adress:).*?\n/g;
str.replace(lookFor, function(match){
var order = match.split(':');
var field = order[0].replace(/\s/g, '');//remove all spaces
var value = order[1];
fields[field]= value;
})
With (Order Number:|Adress:) you are looking for the fields, you can add more fields separated the by the or character | ,inside the parenthessis. The .*?\n operators matches any character till the first break line appears. The g flag indicates that you want to look for all matches. Then you call str.replace, beacause it allows you to perfom a single task on each match. So, if the separator of the field and the value is a colon ':', then you split the match into an array of two values: ['Order number', 12345], and then, store that matches into an object. That code wil produce:
fields = {
OrderNumber: 12345,
Adresss: "my fake adress 000"
}
Please try \n and \r
Example: indexes(str, "\r");
If i've understood well, wat you need is to str.split():
function indexes(source, find) {
var order;
var result = [];
var orders = source.split('\n'); //returns an array of strings: ["order: 12345", "order:54321", ...]
for (var i = 0, l = orders.length; i < l; i++)
{
order = orders[i];
if (order.match(/find/) != null){
result.push(i)
}
}
return result;
}
I'd like to know if it is possible to replace every matching pattern in the string with not one but different values each time.
Let's say I found 5 matches in a text and I want to replace first match with a string, second match with another string, third match with another and so on... is it achievable?
var synonyms = ["extremely", "exceedingly", "exceptionally", "especially", "tremendously"];
"I'm very upset, very distress, very agitated, very annoyed and very pissed".replace(/very/g, function() {
//replace 5 matches of the keyword every with 5 synonyms in the array
});
You may try to replace the matches inside a replace callback function:
var synonyms = ["extremely", "exceedingly", "exceptionally", "especially", "tremendously"];
var cnt = 0;
console.log("I'm very upset, very distress, very agitated, very annoyed and very pissed (and very anxious)".replace(/very/g, function($0) {
if (cnt === synonyms.length) cnt = 0;
return synonyms[cnt++]; //replace 5 matches of the keyword every with 5 synonyms in the array
}));
If you have more matches than there are items in the array, the cnt will make sure the array items will be used from the first one again.
A simple recursive approach. Be sure your synonyms array has enough elements to cover all matches in your string.
let synonyms = ["extremely", "exceedingly", "exceptionally"]
let yourString = "I'm very happy, very joyful, and very handsome."
let rex = /very/
function r (s, i) {
let newStr = s.replace(rex, synonyms[i])
if (newStr === s)
return s
return r(newStr, i+1)
}
r(yourString, 0)
I would caution that if your replacement would also match your regex, you need to add an additional check.
function replaceExpressionWithSynonymsInText(text, regX, synonymList) {
var
list = [];
function getSynonym() {
if (list.length <= 0) {
list = Array.from(synonymList);
}
return list.shift();
}
return text.replace(regX, getSynonym);
}
var
synonymList = ["extremely", "exceedingly", "exceptionally", "especially", "tremendously"],
textSource = "I'm very upset, very distress, very agitated, very annoyed and very pissed",
finalText = replaceExpressionWithSynonymsInText(textSource, (/very/g), synonymList);
console.log("synonymList : ", synonymList);
console.log("textSource : ", textSource);
console.log("finalText : ", finalText);
The advantages of the above approach are, firstly one does not alter the list of synonyms,
secondly working internally with an ever new copy of the provided list and shifting it,
makes additional counters obsolete and also provides the opportunity of being able to
shuffle the new copy (once it has been emptied), thus achieving a more random replacement.
Using the example you've provided, here's what I would do.
First I would set up some variables
var text = "I'm very upset, very distress, very agitated, very annoyed and very pissed";
var regex = /very/;
var synonyms = ["extremely", "exceedingly", "exceptionally", "especially", "tremendously"];
Then count the number of matches
var count = text.match(/very/g).length;
Then I would run a loop to replace the matches with the values from the array
for(var x = 0; x < count; x++) {
text = text.replace(regex, synonyms[x]);
}
You can do it with the use of Replace() function, where you use 'g' option for global matching (finds all occurrences of searched expression). For the second argument you can use a function which returns values from your predefined array.
Here is a little fiddle where you can try it out.
var str = "test test test";
var rep = ["one", "two", "three"];
var ix = 0;
var res = str.replace(/test/g, function() {
if (ix == rep.length)
ix = 0;
return rep[ix++];
});
$("#result").text(res);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<p id="result">
Result...
</p>
Yes it is achievable. There may be a more efficient answer than this, but the brute force way is to double the length of your regex. i.e. Instead of searching just A, search (/A){optionalText}(/A) and then replace /1 /2 as needed. If you need help with the regex itself, provide some code for what you're searching for and someone with more rep than me can probably comment the actual regexp.
Pretty basic but I'm afraid I'm overlooking a simple solution. I have the following string ... IBAN: NL56INGB06716xxxxx ...
I need the accountnumber so I'm looking for indexOf("IBAN: ") but now I need to find the next space/whitespace char after that index.
I don't really think I would need a loop for this but it's the best I can come up with. Regex capture group maybe better? How would I do that?
From MDN String.prototype.indexOf
str.indexOf(searchValue[, fromIndex])
fromIndex
Optional. The location within the calling string to start the search from. It can be any integer. The default value is 0.
n.b. .indexOf will only look for a specific substring, if you want to find a choice from many characters, you will either need to loop and compare or use RegExp
Gracious example
var haystack = 'foo_ _IBAN: Bar _ _';
var needle = 'IBAN: ',
i = haystack.indexOf(needle),
j;
if (i === -1) {
// no match, do something special
console.warn('One cannot simply find a needle in a haystack');
}
j = haystack.indexOf(' ', i + needle.length);
// now we have both matches, we can do something fancy
if (j === -1) {
j = haystack.length; // no match, set to end?
}
haystack.slice(i + needle.length, j); // "Bar"
While you can pass a starting index as Paul suggested, it would seem that a simple regex may just be easier.
var re = /IBAN:\s*(\S+)/
The capture group will hold the sequence of non-whitespace characters after the IBAN:
var match = re.exec(my_str)
if (match) {
console.log(match[1]);
}
Say you have the string, Black cat jack black cat jack black cat jack.
How would you use search() to find the 2nd occurence of the word jack?
I'm guessing the code would look something like:
var str = "Black cat jack black cat jack black cat jack";
var jack = str.search('jack');
But that will only return the location of the first occurrence of jack in the string.
you can use indexof method in a loop
var pos = foo.indexOf("jack");
while(pos > -1) {
pos = foo.indexOf("jack", pos+1);
}
Usage recommendation
Note that String.search method works with RegExp - if you supply a string then it will implicitly convert it into a RegExp. It more or less has the same purpose as RegExp.test, where you only want to know whether there is a match to the RegExp in the string.
If you want to search for fixed string, then I recommend that you stick with String.indexOf. If you really want to work with pattern, then you should use RegExp.exec instead to get the indices of all the matches.
String.indexOf
If you are searching for a fixed string, then you can supply the position to resume searching to String.indexOf:
str.indexOf(searchStr, lastMatch + searchStr.length);
I add searchStr.length to prevent overlapping matches, e.g. searching for abab in abababacccc, there will be only 1 match found if I add searchStr.length. Change it to + 1 if you want to find all matches, regardless of overlapping.
Full example:
var lastMatch;
var result = [];
if ((lastMatch = str.indexOf(searchStr)) >= 0) {
result.push(lastMatch);
while ((lastMatch = str.indexOf(searchStr, lastMatch + searchStr.length)) >= 0) {
result.push(lastMatch);
}
}
RegExp.exec
This is to demonstrate the usage. For fixed string, use String.indexOf instead - you don't need the extra overhead with RegExp in fixed string case.
As an example for RegExp.exec:
// Need g flag to search for all occurrences
var re = /jack/g;
var arr;
var result = [];
while ((arr = re.exec(str)) !== null) {
result.push(arr.index);
}
Note that the example above will give you non-overlapping matches. You need to set re.lastIndex if you want to find overlapping matches (no such thing for "jack" as search string, though).
I've figured out this solution -to call the function that searches and replaces the original string recursively, until no more occurrences of the word are found:
function ReplaceUnicodeChars(myString) {
var pos = myString.search("&#");
if (pos != -1) {
// alert("Found unicode char in string " + myString + ", position " + pos);
unicodeChars = myString.substr(pos, 6);
decimalChars = unicodeChars.substr(2, 3);
myString = myString.replace(unicodeChars, String.fromCharCode(decimalChars));
}
if (myString.search("&#") != -1)
// Keep calling the function until there are no more unicode chars
myString = ReplaceUnicodeChars(myString);
return myString;
}
I want to count the number of occurrence of a specific words in a paragraph.
I am writing my code for key down event. I may have few hundreds words initially that may increase later on.
SO when the user is typing i will match the words in a paragraph and then get the number of occurrence. I also need to make sure that the match will be case sensitive.
Right now i am using this code:
$('.msg').val().split("AP").length - 1
Where AP is the keyword to match.
But i am not very happy with this.
Actually i have a list of few hundred keywords, how can i implement it efficiently.
Please note the words to match have spaces on both side i.e they are boundary words
Any help is appreciated
You can try something like the following:
var wordList = ["some", "word", "or", "other", "CASE", "Sensitive", "is", "required"],
wordCount = [];
for (var i=0; i < wordList.length; i++)
wordCount[i] = 0;
$("#someField").keyup(function(){
var i,
text = this.value,
re;
for (i = 0; i < wordList.length; i++) {
re = new RegExp("\\b" + wordList[i] + "\\b", "g");
wordCount[i] = 0;
while (re.test(text)) wordCount[i]++;
}
});
Demo: http://jsfiddle.net/zMdYg/2/ (updated with longer word list)
I don't really know what you want to do with the results, so I've just stuck them in a simple array, but you can see in the demo I then output them to the page so you can see it working. Obviously you'd substitute your own requirement in that part.
This is using a regex to test each word. You'll notice that with .split() or .indexOf() you'll get partial matches, e.g., if you look for "other" it will also match partway through "bother" (and so forth), but with the regex I've used \b to test on word boundaries.
For a large list of words you might want to create all the regexes in advance rather than redoing them on the fly in the loop, but it seemed to work fine for my simple test so I thought I wouldn't start doing premature optimisations. I'll leave that as an exercise for the reader...
If split() is not case-sensitive, then I would look at using indexOf(), which is case sensitive.
So maybe something like:
var words_array = ['one', 'two', 'three'];
var carot = 0;
var n_occurences = 0;
$.each(words_array, function(index, value){
while(carot < $('.msg').val().length && carot > -1){
carot = $('.msg').val().indexOf(' ' + words_array[index] + ' ', carot);
if (carot > -1){
n_occurences++;
}
}
});
I haven't tested this but I hope you get the idea.