Regex on multiple lines of random order - javascript

I am using BIRT to design a report based on a database, and one of the fields of the form contain multiple lines, like that :
Site: Place ThePlace
Room: D2 RMD3
InstanceId: OI-RandomChars
The fact is, they are not always in this order, as it is user input (in an other form, not BIRT prompt).
And please note that these fields contain capital letters.
So what I want to do is to extract in three separate columns, so with three regex in JavaScript the Site, the Room, and the InstanceId.
I have tried many things with like catching each row until the end of the line or playing around substrings with various conditions ... and so far I think the best to do is to use string function replace to remove anything different than what I want to catch.
An example for the row Room would be :
row["Log"].replace(/?![Room:\s\S*\s]/, "")
I get an error with this but you can see what I try to do.
Thanks for all the consideration about my problem.

A single regex can become overly complicated and hard to read and mantain for this kind of job.
I would probably consider doing it programmatically like your first instinct was.
First I would consider splitting the string into lines
var lines = string.split("\n\n");
This will split all your double lines into an array
["Site: Place ThePlace", "Room: D2 RMD3", "InstanceId: OI-RandomChars"]
Then cycle trough all your lines and then make your checks.
Your check now can actually be regex if you want, or using substring.
This is an example:
var site, room, InstanceId;
var siteCheckRegex = new Regex("^Site:");
for(var i=0; i<lines.length; i++){
if(siteCheckRegex.test(lines[i])){
site = lines[i].replace("Site:","");
}
[...]
}
It actually depends on what you really want to get out of it and the problem and difference you can find in the user input data.

Related

Conditional logic with Enumeration field

I'm creating a CMS using strapi for a client and I would like to give them control of what questions are in a questionnaire. In the questionnaire, each question will be under a section:
-section 1
---question
---question
-section 2
---question
---question
So in strapi I created a collection type with two fields: Section (type enumeration) and Question (type text).
My issue is strapi won't allow me to have spaces in my enumerations so I'm forced to make my section "business_info" when on the site I want to display it as "Business Information". I wrote a simple mapping function (method in vue js) to make it work:
sectionMapping(section) {
switch(section) {
case 'business_info':
return 'Business Information';
case 'target_market':
return 'Target Market';
default:
return 'Section'
}
With this, every time my client wants to add a section to the questionnaire, I would have to do a code update which is not ideal. One solution I came up with was changing section from an enumeration to a text data type, but if my client makes a typo, it would create a whole other section. That's why I like the idea of enumeration.
Any tips?
Thank You
Probably the most dynamic way to accomplish this is to replace underscores with spaces and uppercase the first letter of each word.
First you want to split the string into an array using the split function.
Next you want to iterate over over the resulting array using map, and uppercase the first letter of each word. The example below is take from this question:
section.charAt(0).toUpperCase() + s.slice(1);
Finally join the array of strings together, with a space as a delimiter. When you put everything together you should get a function looking something like:
sectionMapping(section) {
return section.split("_")
.map(s => s.charAt(0).toUpperCase() + section.slice(1))
.join(" ");
}
You will have to change the way you handle default case to return "Section", but this function should eliminate the need to refractor this function each time you want to add a new section title.
I can see I'm a bit late, but maybe it helps someone.
Strapi (not sure from which version) allows you to manually change enums into "unacceptable" forms through code. So you write "business_info", but then, in code, you can turn it into "Business Information". Won't throw up any problems if you do it that way.
This can be done for both components and models. Easy way to find it is to search for "enumeration".
enter image description here
enter image description here

Best way to concatenate multiple strings?

I have a project, where user can put in drop-down values that can be selected. One can select multiple values at a time. So, we have to store the selection and get it on edit mode.
First thought
Let's store them as comma separated in DB.
f.e.
If suggestions are A , B , C and user selects A and B, I was going to store A,B in DB and while getting back the value split it with comma.
Problem arises when user has genuine "comma" in the field, for an instance first,option & second,option. At that time joining with comma won't work.
Second thought
I can think of another option to store it in a stringified array format and parse it while getting back.
For the above instance, it would store the data as ["first,option","second,option"]. It seems to be a good (and only) option for me.
Even though I have a bit of hesitation doing so (which lead me questioning here!) because my users can access the api/DB value directly and for them it doesn't look good.
So, Is there any other way to address this issue to benefit both parties, developers and users? Thanks in advance!!
I'd suggest using a standardized format such as JSON, XML etc.
Serialize and parse and with a widely used library so all escaping of reserved / special characters is done for you. Rolling your own here will cause you problems!
Better yet, use different fields for each suggestion, this is a better design in general. As long as the number of potential fields is finite this will work, e.g. 1-10 suggestions.
If you're going down the JSON route, we can do this in JavaScript like this:
let suggestions = ['Choice A, commas are not, a problem, though punctuation is.', 'Choice B', 'Choice C'];
let json = JSON.stringify(suggestions);
// Save to DB
saveToDB(json);
let jsonFromDB = loadFromDB();
let deserializedSuggestions = JSON.parse(jsonFromDB);
console.log(deserializedSuggestions);
we use semicolon (;) for this exact use case in our current project.
So, as per your question, they will be stored in the DB as option1;option2;option3
and when we get it back from the DB we can use the split() method on it to convert it into an array of substrings.
var str = "option1;option2;option3";
var res = str.split(";");
console.log(res);
which would result in (3) ["option1", "option2", "option3"] in the console.
hope this helps.

Javascript - Update to pipe delimiter with array that contains commas

I've been looking through stack overflow and the internet in general for hours with no solution in site yet...
I'll explain what I'm attempting to do - I'm building a list, then using php explode command by comma so I can loop through it, and insert each record into the database.
However, I'm building the array javascript, and the values I'm building the array off of, contain commas, separating first name and last name (Format Ex: Firstname, Lastname).
I'm a beginner and I'm still learning, so any help to point in the right direction would be greatly appreciated. I'm wondering if I need to do math to count the commas on the php side in order to separate based off the comma count, or if this is achievable in javascript using regex..
Everything I've been looking at seems like I may have to learn some regex to resolve this... Perhaps there's a built in jQuery command to change delimiter that I haven't been able to find?
var labels = $('.list-left ul li.active').map(function(){
return $(this).text().split(',').join('|');
}).get();
Maybe like this:
var test='test1,test2,test3,test4';
var test_new=test.replace(new RegExp(',','g'), '|');
console.log(test_new);

filtering list items based on user's search terms in javascript

I am filtering (showing and hiding) a set of list items based on user's input. check it out here: http://jsfiddle.net/m5dzG/2/
Question:
Try inputing the word "comparison" you will see that the list hides except the ones that has the word "comparison" in them. good so far... but if you hit space and add more terms like the word "extrapolated" that is exist in that string it will find list items that have either of those words. What I want is AND not OR. basically I want to show the list item that has both those words in it. Because as you can imagine by putting more terms the list gets bigger not smaller.
I think the problem is in my regular expression in this line
var search_text = jQuery('#search').val();
var rg= new RegExp('('+$.unique(search_text.split(" ")).join("|")+')',"i");
any help would be appreciated.
Thanks
Try this. It should make a string like this: ^(?=.*?honda)(?=.*?accord). This way, the string must have each of the terms somewhere in the string.
var search_text = jQuery('#search').val();
var rg= new RegExp('^(?=.*?'+$.unique(search_text.split(" ")).join(")(?=.*?")+')',"i");

jQuery "Autocomplete" plugin is messing up the order of my data

I'm using Jorn Zaefferer's Autocomplete plugin on a couple of different pages. In both instances, the order of displayed strings is a little bit messed up.
Example 1: array of strings: basically they are in alphabetical order except for General Knowledge which has been pushed to the top:
General Knowledge,Art and Design,Business Studies,Citizenship,Design and Technology,English,Geography,History,ICT,Mathematics,MFL French,MFL German,MFL Spanish,Music,Physical Education,PSHE,Religious Education,Science,Something Else
Displayed strings:
General Knowledge,Geography,Art and Design,Business Studies,Citizenship,Design and Technology,English,History,ICT,Mathematics,MFL French,MFL German,MFL Spanish,Music,Physical Education,PSHE,Religious Education,Science,Something Else
Note that Geography has been pushed to be the second item, after General Knowledge. The rest are all fine.
Example 2: array of strings: as above but with Cross-curricular instead of General Knowledge.
Cross-curricular,Art and Design,Business Studies,Citizenship,Design and Technology,English,Geography,History,ICT,Mathematics,MFL French,MFL German,MFL Spanish,Music,Physical Education,PSHE,Religious Education,Science,Something Else
Displayed strings:
Cross-curricular,Citizenship,Art and Design,Business Studies,Design and Technology,English,Geography,History,ICT,Mathematics,MFL French,MFL German,MFL Spanish,Music,Physical Education,PSHE,Religious Education,Science,Something Else
Here, Citizenship has been pushed to the number 2 position.
I've experimented a little, and it seems like there's a bug saying "put things that start with the same letter as the first item after the first item and leave the rest alone". Kind of mystifying. I've tried a bit of debugging by triggering alerts inside the autocomplete plugin code but everywhere i can see, it's using the correct order. it seems to be just when its rendered out that it goes wrong.
Any ideas anyone?
max
EDIT - reply to Clint
Thanks for pointing me at the relevant bit of code btw. To make diagnosis simpler i changed the array of values to ["carrot", "apple", "cherry"], which autocomplete re-orders to ["carrot", "cherry", "apple"].
Here's the array that it generates for stMatchSets:
stMatchSets = ({'':[#1={value:"carrot", data:["carrot"], result:"carrot"}, #3={value:"apple", data:["apple"], result:"apple"}, #2={value:"cherry", data:["cherry"], result:"cherry"}], c:[#1#, #2#], a:[#3#]})
So, it's collecting the first letters together into a map, which makes sense as a first-pass matching strategy. What i'd like it to do though, is to use the given array of values, rather than the map, when it comes to populating the displayed list. I can't quite get my head around what's going on with the cache inside the guts of the code (i'm not very experienced with javascript).
SOLVED - i fixed this by hacking the javascript in the plugin.
On line 549 (or 565) we return a variable csub which is an object holding the matching data. Before it's returned, I reorder this so that the order matches the original array of value we were given, ie that we used to build the index in the first place, which i had put into another variable:
csub = csub.sort(function(a,b){ return originalData.indexOf(a.value) > originalData.indexOf(b.value); })
hacky but it works. Personally i think that this behaviour (possibly coded more cleanly) should be the default behaviour of the plugin: ie, the order of results should match the original passed array of possible values. That way the user can sort their array alphabetically if they want (which is trivial) to get the results in alphabetical order, or they can preserve their own 'custom' order.
What I did instead of your solution was to add
if (!q && data[q]){return data[q];}
just above
var csub = [];
found in line ~535.
What this does, if I understood correctly, is to fetch the cached data for when the input is empty, specified in line ~472: stMatchSets[""] = []. Assuming that the cached data for when the input is empty are the first data you provided to begin with, then its all good.
I'm not sure about this autocomplete plugin in particular, but are you sure it's not just trying to give you the best match possible? My autocomplete plugin does some heuristics and does reordering of that nature.
Which brings me to my other answer: there are a million jQuery autocomplete plugins out there. If this one doesn't satisfy you, I'm sure there is another that will.
edit:
In fact, I'm completely certain that's what it's doing. Take a look around line 474:
// loop through the array and create a lookup structure
for ( var i = 0, ol = options.data.length; i < ol; i++ ) {
/* some code */
var firstChar = value.charAt(0).toLowerCase();
// if no lookup array for this character exists, look it up now
if( !stMatchSets[firstChar] )
and so on. So, it's a feature.

Categories