Remove everything else from the String using regular expression - regex

I have this regular expression which is what is allowed in the String.
^\pL*['#-]?\pL*\$
The requirements have changed and now I need to drop everything else from the String. For example only one of these special characters ', #, and - is allowed.
How can I change this regex to drop everything else that does not fit this ?
Here is the list of expected values:
JohnO'Connell -> allowed. should be as is.
JohnDias -> allowed. should be as is.
JohnOConnell' -> allowed. should be as is.
JohnOConnell# -> allowed. should be as is.
JohnOConnell- -> allowed. should be as is.
JohnOConnell-# -> should return JohnOConnell-
JohnOConn34ell -> should return JohnOConnell
*JohnOConnell -> should return JohnOConnell
JohnOConnell* -> should return JohnOConnell
JohnOConn$%ell -> should return JohnOConnell
Thanks

If I understand it correctly, you could do it this way:
// Test data
def tests = [ [ input:"JohnO'Connell", output:"JohnO'Connell" ],
[ input:"JohnDias", output:"JohnDias" ],
[ input:"JohnOConnell'", output:"JohnOConnell'" ],
[ input:"JohnOConnell#", output:"JohnOConnell#" ],
[ input:"JohnOConnell-", output:"JohnOConnell-" ],
[ input:"JohnOConnell-#", output:"JohnOConnell-" ],
[ input:"JohnOConn34ell", output:"JohnOConnell" ],
[ input:"*JohnOConnell", output:"JohnOConnell" ],
[ input:"JohnOConnell*", output:"JohnOConnell" ],
[ input:"JohnOConn\$%ell", output:"JohnOConnell" ] ]
String normalize( String input ) {
int idx = 0
input.replaceAll( /[^A-Za-z'#\-]/, '' ) // remove all disallowed chars
.replaceAll( /['#\-]/ ) { match -> // replace 2nd+ instance of special chars
idx++ == 0 ? match : ''
}
}
tests.each {
assert normalize( it.input ) == it.output
}

Related

how read list inside list on dart(FLUTTER)

final List _icons = [
[
'IDENTITY',
FontAwesomeIcons.camera,
],
[
'SPECIES',
FontAwesomeIcons.tree,
],
[
'ARTICLES',
FontAwesomeIcons.bookOpen,
],
];
You can try
_icons[0][1] //FontAwesomeIcons.camera
but it seems like you can use a map instead of a list
final map _icons = { 'IDENTITY' : FontAwesomeIcons.camera, 'SPECIES': FontAwesomeIcons.tree, 'ARTICLES' : FontAwesomeIcons.bookOpen};
_icons['IDENTITY']; //FontAwesomeIcons.camera

Combining usage of Terraform's zipmap, maps, and lists

I have two different scenarios, one with public subnets and one with private.
For both, I would like to apply some combination of for-loop and zipmask to have a single map object. You can assume I have checked the ordering of the two input maps/lists and that they are align.
Using the public-subnet as the first example, I have one cidr for each user:
pub_cidr_map = {
"user2" = "10.0.8.0/21"
"user4" = "10.0.24.0/21"
"user1" = "10.0.0.0/21"
"user3" = "10.0.16.0/21"
}
pub_id_list = [
"subnet-666666662ee6f3442",
"subnet-6666666696b92d895",
"subnet-66666666cbaa4bfb3",
"subnet-6666666655a09d064",
]
I would like this to look like this so I can access both values with a single key:
pub_lookup_map = {
"user2" = ["10.0.8.0/21", "subnet-666666662ee6f3442"]
"user4" = ["10.0.24.0/21", "subnet-6666666696b92d895"]
"user1" = ["10.0.0.0/21", "subnet-66666666cbaa4bfb3"]
"user3" = ["10.0.16.0/21", "subnet-6666666655a09d064"]
}
I'd also like to accomplish something similar with my private subets, which are apportioned two-per-user:
priv_cidr_map = {
"user1" = [
"10.0.96.0/20",
"10.0.112.0/20",
]
"user2" = [
"10.0.160.0/20",
"10.0.176.0/20",
]
"user3" = [
"10.0.64.0/20",
"10.0.80.0/20",
]
"user4" = [
"10.0.128.0/20",
"10.0.144.0/20",
]
}
priv_id_list = [
"subnet-666666662f611f9a5",
"subnet-6666666689f1eff5e",
"subnet-66666666a3fe6efb9",
"subnet-66666666faf4a62a8",
"subnet-666666668f1442700",
"subnet-66666666328a4b134",
"subnet-666666661b147a933",
"subnet-666666661ce02c330"
]
I would like this to look like
priv_lookup_map = {
"user1" = [
["10.0.96.0/20","subnet-666666662f611f9a5"]
["10.0.112.0/20","subnet-6666666689f1eff5e"]
]
"user2" = [
["10.0.160.0/20","subnet-66666666a3fe6efb9"]
["10.0.176.0/20","subnet-66666666faf4a62a8"]
]
"user3" = [
["10.0.64.0/20","subnet-666666668f1442700"]
["10.0.80.0/20","subnet-66666666328a4b134"]
]
"user4" = [
["10.0.128.0/20","subnet-666666661b147a933"]
["10.0.144.0/20","subnet-666666661ce02c330"]
]
}
I am open to any other structures someone might think are useful; the use case here is to provision subnets and EIPs as part of a separate, stateful deployment of a VPC prior to the deployment of the resources (like EC2, RDS) that will reside within these ranges.
I can not guarantee that this solution is correct, I will share my attempt anyway hoping it might be helpful.
For the public subnets:
locals {
pub_lookup_map = {for key, value in zipmap(keys(var.pub_cidr_map), var.pub_id_list) : key => [var.pub_cidr_map[key], value] }
}
This will produce the following output:
pub = {
"user1" = [
"10.0.0.0/21",
"subnet-666666662ee6f3442",
]
"user2" = [
"10.0.8.0/21",
"subnet-6666666696b92d895",
]
"user3" = [
"10.0.16.0/21",
"subnet-66666666cbaa4bfb3",
]
"user4" = [
"10.0.24.0/21",
"subnet-6666666655a09d064",
]
}
The problem with this output is that, as I noted in the comments, the iteration over a the keys of a map happens in a lexicographical order. This means that user1 will be mapped to the first entry from pub_id_list, user2 to the second entry, etc. Even if you are suggesting in the comments that "I've checked this ordering issue and not to worry about it", please double check this solution before using it.
For the private subnets:
locals {
cidr_subnet_id = zipmap(flatten(values(var.priv_cidr_map)), var.priv_id_list)
priv_lookup_map = {for key, value in var.priv_cidr_map: key => [ for cidr in value: [cidr, local.cidr_subnet_id[cidr]]]}
}
Please note, that I'm using an intermediary local variable to make my code readable. The value for cidr_subnet_id will be:
cidr_subnet_id = {
"10.0.112.0/20" = "subnet-6666666689f1eff5e"
"10.0.128.0/20" = "subnet-666666661b147a933"
"10.0.144.0/20" = "subnet-666666661ce02c330"
"10.0.160.0/20" = "subnet-66666666a3fe6efb9"
"10.0.176.0/20" = "subnet-66666666faf4a62a8"
"10.0.64.0/20" = "subnet-666666668f1442700"
"10.0.80.0/20" = "subnet-66666666328a4b134"
"10.0.96.0/20" = "subnet-666666662f611f9a5"
}
This is essentially a map between the CIDR and the subnet id. Apparently, this works correctly, because the keys from the priv_lookup_map are in lexicographical order when provided. I think this somewhat answers your question in the comments for "if both maps are in lexigraphical order isn't this a non-issue?"
The output for priv_lookup_map will be:
priv = {
"user1" = [
[
"10.0.96.0/20",
"subnet-666666662f611f9a5",
],
[
"10.0.112.0/20",
"subnet-6666666689f1eff5e",
],
]
"user2" = [
[
"10.0.160.0/20",
"subnet-66666666a3fe6efb9",
],
[
"10.0.176.0/20",
"subnet-66666666faf4a62a8",
],
]
"user3" = [
[
"10.0.64.0/20",
"subnet-666666668f1442700",
],
[
"10.0.80.0/20",
"subnet-66666666328a4b134",
],
]
"user4" = [
[
"10.0.128.0/20",
"subnet-666666661b147a933",
],
[
"10.0.144.0/20",
"subnet-666666661ce02c330",
],
]
}

Terraform - transform list of lists to into a new list of lists

In Terraform, I need to transform my input data structure from e.g.:
vip_lists = [
["1.0.1.1", "1.0.1.2", "1.0.1.3", "1.0.1.4"]
["1.0.2.1", "1.0.2.2", "1.0.2.3", "1.0.2.4"]
["1.0.0.1", "1.0.0.2", "1.0.0.3", "1.0.0.4"]
]
to produce an output like this:
vip_sets = [
["1.0.1.1", "1.0.2.1", "1.0.0.1"]
["1.0.1.2", "1.0.2.2", "1.0.0.2"]
["1.0.1.3", "1.0.2.3", "1.0.0.3"]
["1.0.1.4", "1.0.2.4", "1.0.0.4"]
]
So essentially, i need to take my input list of lists and create an output which is again a list of lists but whose 0th list is a list of the 0th elements from each of the lists in the input...then the same again for the 1st and so on.
I can't know in advance how many lists will be in the input or how long they will be, but we can assume the lists will all be the same length if that helps.
I've tried pretty much everything I can think of and searched the web but since with no luck. All suggestions would be very welcome!
I once wrote version of this for lists of lists that are not the same length for one of our modules on github.com/mineiros-io where we used such transformations to create 2 dimensional sets of resources using count. (Those are not in use atm as we transformed them to maps for use with ressource level for_each).
locals {
matrix = [
["1.0.1.1", "1.0.1.4"],
["1.0.2.1", "1.0.2.2", "1.0.2.3", "1.0.2.4"],
["1.0.0.1", "1.0.0.3", "1.0.0.4"]
]
row_lengths = [
for row in local.matrix : length(row)
]
max_row_length = max(0, local.row_lengths...)
output = [
for i in range(0, local.max_row_length) : [
for j, _ in local.matrix : try(local.matrix[j][i], null)
]
]
output_compact = [
for i in range(0, local.max_row_length) : compact([
for j, _ in local.matrix : try(local.matrix[j][i], null)
])
]
}
output "matrix" {
value = local.output
}
output "compact" {
value = local.output_compact
}
which can handle dynamic list sizes and output them compact or filled with null values:
Outputs:
compact = [
[ "1.0.1.1", "1.0.2.1", "1.0.0.1" ],
[ "1.0.1.4", "1.0.2.2", "1.0.0.3" ],
[ "1.0.2.3", "1.0.0.4" ],
[ "1.0.2.4" ],
]
matrix = [
[ "1.0.1.1", "1.0.2.1", "1.0.0.1" ],
[ "1.0.1.4", "1.0.2.2", "1.0.0.3" ],
[ null, "1.0.2.3", "1.0.0.4" ],
[ null, "1.0.2.4", null ],
]
I know an answer is already accepted, but maybe some one can still make use of this dynamic version.
This is sort of horrible, but it works (Although I haven't tested what it'd do if vip_lists was empty. Probably crash, as I'm indexing to vip_lists[0] without checking):
locals {
vip_lists = [
["1.0.1.1", "1.0.1.2", "1.0.1.3", "1.0.1.4"],
["1.0.2.1", "1.0.2.2", "1.0.2.3", "1.0.2.4"],
["1.0.0.1", "1.0.0.2", "1.0.0.3", "1.0.0.4"]
]
vip_sets = [for i in range(0, length(local.vip_lists[0])): [for j in range(0, length(local.vip_lists)): local.vip_lists[j][i]]]
}
output "vip_sets" {
value = local.vip_sets
}
$ terraform apply
Apply complete! Resources: 0 added, 0 changed, 0 destroyed.
Outputs:
vip_sets = [
[
"1.0.1.1",
"1.0.2.1",
"1.0.0.1",
],
[
"1.0.1.2",
"1.0.2.2",
"1.0.0.2",
],
[
"1.0.1.3",
"1.0.2.3",
"1.0.0.3",
],
[
"1.0.1.4",
"1.0.2.4",
"1.0.0.4",
],
]

Customized Reordering/Sorting of a List in Perl in O(n)

I am re-ordering a list.
My OrignalList, INPUT: #lineItems
[
{id=> 'id1', ..},
{id=> 'id2', 'groupId'=>45D,.. },
{id=> 'id3', 'groupId'=>56A, .. },
{id=> 'id4', 'groupId'=>45D, 'isParent'=>1 .. },
{id=> 'id5', ..},
{id=> 'id6', 'groupId'=>56A, 'isParent'=>1.. },
]
In above list, groupId signifies that the item is a part of bundle. GroupId uniquely determines the bundle group. If group Id is not present then its a non bundle item.
Aim - To re-order the list such that all the bundle items should be grouped together with parent item in the starting of every bundle and the incoming order of the bundle and non bundle items (when groupId not present) should remain unchanged.
To sort the list in O(n)
Expected Output:
[
{id=> 'id1', ..},
{id=> 'id4', 'groupId'=>45D, 'isParent'=>1 .. },
{id=> 'id2', 'groupId'=>45D,.. },
{id=> 'id6', 'groupId'=>56A, 'isParent'=>1.. },
{id=> 'id3', 'groupId'=>56A, .. },
{id=> 'id5', ..},
]
Here my Algo:
Create a sortedList of Ids = #sortedLineitemsIds
Use sortedIdsList to form the final sorted list
Code for #1
my $grouIdToLineItemIdMap;
foreach my $lineItem (#$lineItems) {
if(!$lineItem->{'groupID'}) { #non bundle item, add as it is
push #sortedLineitemsIds, $lineItem->{'id'};
} else {
if($lineItem->{'IsParent'} eq 1) {
unshift #{$grouIdToLineItemIdMap->{$groupId}}, $lineItem->{'id'};
} else {
push #{$grouIdToLineItemIdMap->{$groupId}}, $lineItem->{'id'};
}
}
}
push #sortedLineitemsIds, $grouIdToLineItemIdMap; # **[[Question 1]]** This will always add bundle items at the end irrespective of whether it was in starting or end.
Now this will yield sortedLineitemsIds =>
$VAR1 = [
'id1',
'id5',
{
'45D' => [
'id4:',
'id2:'
],
'56A' => [
'id6:',
'id3:'
]
}
];
Code for #2
foreach my $Id (#sortedLineitemsIds) {
if(determineIfSingleIdOrMapOfGroupId) { #**[[Question 2]]**
my $lineItem = grep #lineItems with $Id; #**[[Question 3]]**
push #sortedLineItems, $lineItem;
} else {
my $listOfLineItemsForGroupId = $sortedLineitemsIds->{$Id};
foreach groupLineItemId (#$listOfLineItemsForGroupId) {
my $lineItem = grep #lineItems with groupLineItemId; #**[[Question 3]]**
push #sortedLineItems, $lineItem;
}
}
}
I have now 3 questions marked above at different places in the code:
Question 1 -> Here I dont want to change the incoming order of
items. Just group them. But what I am doing is it is pushing all the
lineItems of the group in map, which I am appending at end after the
loop. How can I can do that in the loop to preserve that order?
Question 2 -> How can I determine whether it is a single Id (non
bundle id) or a groupID (basically a ref containing the
lineItemIds)?
Question 3 -> How can I grep the orginal list based on
the 'id' and get the corresponding lineItem?
You say you don't want to change the order of the items, but that's clearly not true. I'm going to assume you meant this:
I want to preserve the relative order of items which are either independent or the first of their group.
This can indeed be done in O(N).
We're going to build this:
my #grouped = (
[ $lineItem_id1 ],
[ $lineItem_id4, $lineItem_id2 ],
[ $lineItem_id6, $lineItem_id3 ],
[ $lineItem_id5 ],
);
To achieve that, we're going to use the following algorithm:
For each item,
If the item is independent,
Add it to #grouped.
Else,
Lookup if we've encountered the item's group before.
If the item is part of a group we haven't encountered before,
If it's the parent,
Add it to start of the existing group.
Else,
Add it to end of the existing group.
Else,
Create a new group from the item.
Add the new group to #grouped.
Add the new group to the lookup hash.
At the end of this, we'll end up with the following:
my $group_45D = [ $lineItem_id4, $lineItem_id2 ];
my $group_56A = [ $lineItem_id6, $lineItem_id3 ];
my %groups = (
'45D' => $group_45D,
'56A' => $group_56A,
);
my #grouped = (
[ $lineItem_id1 ],
$group_45D,
$group_56A,
[ $lineItem_id5 ],
);
Solution:
my #grouped;
{
my %groups;
for my $lineItem (#$lineItems) {
if ( my $groupId = $lineItem->{groupId} ) {
if (!$groups{$groupId}) {
push #grouped, $groups{$groupId} = [];
}
if ($lineItem->{isParent}) {
unshift #{ $groups{$groupId} }, $lineItem;
} else {
push #{ $groups{$groupId} }, $lineItem;
}
} else {
push #grouped, [ $lineItem ];
}
}
}
Finally, we simply need to flatten the list.
my #ordered = map { #$_ } #grouped;
Tested.

PEG.js help - optional free text followed by key value pairs

I wrote the following parser (paste into http://pegjs.org/online and it works):
Expression = Pairs / FullTextWithPairs
Pairs = (';'? _ p:Pair { return p; })*
FullTextWithPairs = fto:FullText po:Pairs
{
var arr = [];
if (fto) {
arr.push(fto);
}
return arr.concat(po);
}
FullText = ft:ValueString ';'
{
return {'key' : 'fullText', 'op': '=', 'value': ft};
}
Pair = k:Field op:Operator v:ValueString
{
var res = {'key' : k, 'op': op, 'value': v};
console.log(res);
return res;
}
Operator = ('<>' / [=><])
ValueString = vs:[^;]+ {return vs.join('');}
Field = 'location' / 'application' / 'count'
_ = ' '*
It parses this string of key-value pairs: location=USA; application<>app; count>5
to this:
[
{
"key": "location",
"op": "=",
"value": "USA"
},
{
"key": "application",
"op": "<>",
"value": "app"
},
{
"key": "count",
"op": ">",
"value": "5"
}
]
The problem is I want to enable a free-text search as well, which is entered before the key-value pairs, for example:
this: free text foobar; location=USA; application<>app; count>5
and get this:
[
{
"key": "fullText",
"op": "=",
"value": "free text foobar"
},
{
"key": "location",
"op": "=",
"value": "USA"
},
{
"key": "application",
"op": "<>",
"value": "app"
},
{
"key": "count",
"op": ">",
"value": "5"
}
]
The parser should recognize that the first part is not a key-value pair (according to "Pair" rule) and insert it as "fullText" object.
Basically "Expression" rule should do it, according to what I read in the docs - A / B means if A doesn't pass the B is tried. In the second case "Paris" is faild because "free text foobar" doesn't pass the Pairs rule, but it just throws an exception instead of moving on.
Congrats to whomever survived up to here, what am I doing wrong? :)
Thank you
Played with the grammar some more, the solution was to use !Pair and (for some reason) to change the order of the "Expression" rule:
Expression = FullTextWithPairs / Pairs
Pairs = (';'? _ p:Pair { return p; })*
FullTextWithPairs = fto:FullText po:Pairs
{
var arr = [];
if (fto) {
arr.push(fto);
}
return arr.concat(po);
}
FullText = !Pair ft:ValueString ';'
{
return {'key' : 'fullText', 'op': '=', 'value': ft};
}
Pair = _? k:Field op:Operator v:ValueString
{
var res = {'key' : k, 'op': op, 'value': v};
console.log(res);
return res;
}
Operator = ('<>' / [=><])
ValueString = vs:[^;]+ {return vs.join('');}
Field = 'location' / 'application' / 'count'
_ = ' '*