Regex: Exclude matches containing specific strings - regex

I'm not really versatile in regex, especially multi-line so i hope someone can help me out here.
Based on the following example, I'm trying to find all the field definitions of type Code that don't have the "TableRelation"-property set.
so in this example, this would be the field "Holding Name"
table 123 "MyTable"
{
fields
{
field(1000; "Created on"; Date)
{
Caption = 'Created on';
DataClassification = CustomerContent;
Editable = false;
}
field(2000; "Created by"; Code[50])
{
Caption = 'Created by';
TableRelation = User."User Name";
DataClassification = CustomerContent;
Editable = false;
}
field(3000; Resigned; Boolean)
{
Caption = 'Resigned';
DataClassification = CustomerContent;
}
field(4000; "Holding No."; Code[20])
{
Caption = 'Holding No.';
TableRelation = Contact."No." where(Type = const(Company));
DataClassification = CustomerContent;
trigger OnValidate()
var
[...]
begin
[...]
end;
}
field(4010; "Holding Name"; Code[100])
{
Caption = 'Holding Name';
DataClassification = CustomerContent;
}
field(5000; "Geocoding Entry No."; Integer)
{
Caption = 'Geocoding Entry No.';
DataClassification = CustomerContent;
}
}
keys
{
key(AppliesToContact; "Holding No.", "Holding Name", "Company Level") { }
}
}
I Managed to match the fields of type "Code" properly... field\(\d+;.+; ?(?:C|c)ode\[\d+\]\)\n?\s*\{(?:\n|.)*?\}
But i don't know how to correctly exclude matches containing "TableRelation" at least this doesn't work the way I hoped. - I get one HUGE match with it :-(
field\(\d+;.+; ?(?:C|c)ode\[\d+\]\)\n?\s*\{((?!(T|t)able(R|r)elation)\n*.*)*?\}
p.s. if you're wondering: The sample I'm parsing is written in AL-Language, a proprietary language for MS Business central.

You can match field( and the digits between the square brackets before the closing parenthesis using a negated character class starting with [^
The same negated character class approach can also be taken for asserting not TableRelation between curly braces.
Not that you can write (?:C|c) as [Cc] using a character class instead of using an alternation |
Assuming the curly brace after field has a single non nested closing curly:
field\([^()]+; ?[Cc]ode\[\d+\]\)\s*{(?![^{}]*[Tt]able[Rr]elation)[^{}]*}
The pattern matches:
field\([^()]+ Match field( and 1+ chars other than ( ) (which can also match a newline)
; ?[Cc]ode Match ; optional space and Code/code
\[\d+\]\) Match [ 1+ digits ])
\s*{ Match optional whitespace chars (which can also match a newline) and {
(?![^{}]*[Tt]able[Rr]elation) Negative lookahead, assert not TableRelation after the openin curly
[^{}]* Match optional repetitions of any character except { }
} Match closing }
See a regex demo.

With a caseless research and with a regex engine that allows atomic groups and possessive quantifiers, you can write:
\bfield\((?>[^);]*;\s*)*code\b[^)]*\)\s*{(?>[^\w}]*+(?!tablerelation\s*=)\w+)*[^\w}]*}
demo
This pattern is based on negative character classes to stop the greedy quantifiers as in The four birds answer.
Atomic groups (?>...) and possessive quantifiers *+ are used to reduce the backtracking. In particular, the presence of tablerelation is only tested after a range of non-word characters with a negative lookahead.
Note that the code part can be everywhere between the parenthesis after field.

The following regex can capture the Code[...] value of areas not having 'TableRelation'.
/field\([^)]+; Code\[(\d+)\]\)\n\s+{((?!TableRelation).)+?}\n/gs
It uses g(global) and s(dotall) flags.
A notable part of this regexp is the ((?!TableRelation).)+? expression.
(?!TableRelation) : negative lookahead(should not appear)
((?!TableRelation).)+? : not having 'TableRelation', match as few as possible
I created a simple JS snippet. The code uses two steps to extract.
const regexp = /field\([^)]+; Code\[(\d+)\]\)\n\s+{((?!TableRelation).)+?}\n/gs;
const target = `
table 123 "MyTable"
{
fields
{
field(1000; "Created on"; Date)
{
Caption = 'Created on';
DataClassification = CustomerContent;
Editable = false;
}
field(2000; "Created by"; Code[50])
{
Caption = 'Created by';
TableRelation = User."User Name";
DataClassification = CustomerContent;
Editable = false;
}
field(3000; Resigned; Boolean)
{
Caption = 'Resigned';
DataClassification = CustomerContent;
}
field(4000; "Holding No."; Code[20])
{
Caption = 'Holding No.';
TableRelation = Contact."No." where(Type = const(Company));
DataClassification = CustomerContent;
trigger OnValidate()
var
[...]
begin
[...]
end;
}
field(4010; "Holding Name"; Code[100])
{
Caption = 'Holding Name';
DataClassification = CustomerContent;
}
field(4050; "Holding Name"; Code[80])
{
Caption = 'Holding Name 2';
DataClassification = CustomerContent;
}
field(5000; "Geocoding Entry No."; Integer)
{
Caption = 'Geocoding Entry No.';
DataClassification = CustomerContent;
}
}
keys
{
key(AppliesToContact; "Holding No.", "Holding Name", "Company Level") { }
}
}
`;
// step 1: extract field(...){...} chunks that do not contain "TableRelation"
const matchedBlocks = target.match(regexp);
// step 2: extract code values
const codes = matchedBlocks.map(m => m.match(/; Code\[(\d+)\]/)[1] );
console.log(codes);

Related

How to get integer with regular expression in kotlin?

ViewModel
fun changeQty(textField: TextFieldValue) {
val temp1 = textField.text
Timber.d("textField: $temp1")
val temp2 = temp1.replace("[^\\d]".toRegex(), "")
Timber.d("temp2: $temp2")
_qty.value = textField.copy(temp2)
}
TextField
OutlinedTextField(
modifier = Modifier
.focusRequester(focusRequester = focusRequester)
.onFocusChanged {
if (it.isFocused) {
keyboardController?.show()
}
},
value = qty.copy(
text = qty.text.trim()
),
onValueChange = changeQty,
label = { Text(text = qtyHint) },
singleLine = true,
keyboardOptions = KeyboardOptions(
keyboardType = KeyboardType.Number,
imeAction = ImeAction.Done
),
keyboardActions = KeyboardActions(
onDone = {
save()
onDismiss()
}
)
)
Set KeyboardType.Number, it display 1,2,3,4,5,6,7,8,9 and , . - space.
I just want to get integer like -10 or 10 or 0.
But I type the , or . or -(not the front sign), it show as it is.
ex)
typing = -10---------
hope = -10
display = -10---------
I put regular expression in
val temp2 = temp1.replace("[^\\d]".toRegex(), "")
But, it doesn't seem to work.
How I can get only integer(also negative integer)?
Use this regex (?<=(\d|-))(\D+) to replace all non digit characters, except first -.
fun getIntegersFromString(input: String): String {
val pattern = Regex("(?<=(\\d|-))(\\D+)")
val formatted = pattern.replace(input, "")
return formatted
}
Check it here

how to create a filter to search for a word with special characters while writing in the input without special characters

it's my first post.
I work to Quasar (Vue.js)
I have list of jobs, and in this list, i have words with special caractere.
Ex :
[ ...{ "libelle": "Agent hôtelier" },{"libelle": "Agent spécialisé / Agente spécialisée des écoles maternelles -ASEM-"},{ "libelle": "Agriculteur / Agricultrice" },{ "libelle": "Aide aux personnes âgées" },{ "libelle": "Aide de cuisine" },...]
And on "input" i would like to search "Agent spécialisé" but i want to write "agent specialise" (without special caractere) or the initial name, i want to write both and autocomplete my "input".
I just don't fin the solution for add to my filter code ...
My input :
<q-select
filled
v-model="model"
use-input
hide-selected
fill-input
input-debounce="0"
:options="options"
hint="Votre métier"
style="width: 250px; padding-bottom: 32px"
#filter="filterFn"
>
</q-select>
</div>
My code :
export default {
props: ['data'],
data() {
return {
jobList: json,
model: '',
options: [],
stringOptions: []
}
},
methods: {
jsonJobsCall(e) {
this.stringOptions = []
json.forEach(res => {
this.stringOptions.push(res.libelle)
})
},
filterFn(val, update) {
if (val === '') {
update(() => {
this.jsonJobsCall(val)
this.options = this.stringOptions
})
return
}
update(() => {
const regex = /é/i
const needle = val.toLowerCase()
this.jsonJobsCall(val)
this.options = this.stringOptions.filter(
v => v.replace(regex, 'e').toLowerCase().indexOf(needle) > -1
)
})
},
}
}
To sum up : i need filter for write with or witouth special caractere in my input for found in my list the job which can contain a special character.
I hope i was clear, ask your questions if i haven't been.
Thanks you very much.
I am not sure if its work for you but you can use regex to create valid filter for your need. For example, when there is "e" letter you want to check "e" or "é" (If I understand correctly)
//Lets say we want to match "Agent spécialisé" with the given search text
let searchText = "Agent spe";
// Lets create a character map for matching characters
let characterMap = {
e: ['e', 'é'],
a: ['a', '#']
}
// Replacing special characters with a regex part which contains all equivelant characters
// !Remember replaceAll depricated
Object.keys(characterMap).forEach((key) => {
let replaceReg = new RegExp(`${key}`, "g")
searchText = searchText.replace(replaceReg, `[${characterMap[key].join("|")}]`);
})
// Here we create a regex to match
let reg = new RegExp(searchText + ".*")
console.log("Agent spécialisé".match(reg) != null);
Another approach could be the reverse of this. You can normalize "Agent spécialisé". (I mean replace all é with normal e with a regex like above) and store in the object along with the original text. But search on this normalized string instead of original.

What is wrong with the validation of the form

For some reason validation of the form does not work - it allows empty field submitting, what's wrong?
TextFormField(
validator: (val) {
if (val.trim().length == 0) {
return Lang.key(context, 'wrongDeviceName');
} else {
return null;
}
},
onSaved: (val) =>
_name = toBeginningOfSentenceCase(val.trim()),
initialValue:
id == 0 ? '' : model.byId(id, tableName).name.toString(),
keyboardType: TextInputType.visiblePassword,
),
How can I fix it?
You may declare a validateDeviceName function in the validator and implement it:
validator: validateDeviceName
And then
String validateDeviceName(String value)
{
RegExp regex = new RegExp(r'^[A-Za-z0-9\s]*$');
if (!regex.hasMatch(value))
return 'Enter Valid Device Name';
else
return null;
}
The ^[A-Za-z0-9\s]*$ regex matches
^ - start of string
[A-Za-z0-9\s]* - 0 or more (*) characters that are either ASCII letters (A-Za-z), digits (0-9) or whitespace (\s)
$ - end of string.
See the regex demo.
There are some good hints about Form Validation in Flutter here.

Regex : capturing group?

I was wondering if it is possible to use capturing groups with MongoDB.
For example, assuming I have a collection of users with only their full name, and I want to get their first and last name.
Here's what I was thinking of using capturing groups :
bulk.find( { full_name: /<first_name>(.*) <last_name>(.*)/i } ).upsert().replaceOne(
{
first_name: <first_name>,
last_name: <last_name>
}
);
bulk.execute();
Is it possible using only MongoDB ? How would you do that ?
Maybe using javascript :
doc here : http://docs.mongodb.org/manual/reference/method/cursor.forEach/
Example :
db.collection.find().forEach(function(e) {
var fullName = e.full_name
e.firstname = full_name.substring(\*something*\)
e.lastname = full_name.substring(\*something*\)
db.collection.save(e);
});
MongoDB version 4.2 (released in August 2019) provides the
regexFind operator. From the documentation:
Provides regular expression (regex) pattern matching capability in
aggregation expressions. If a match is found, returns a document that
contains information on the first match... If your regex pattern
contains capture groups and the pattern finds a match in the input,
the captures array in the results corresponds to the groups captured
by the matching string.
Syntax:
{ $regexFind: { input: <expression> , regex: <expression>, options: <expression> } }
E.g. (I didn't verify your regex does what you want)
db.collection.aggregate([
{
$project: {
names: {
$regexFind: { input: "$phone", regex: /(.*) (.*)/i }
}
}
}
])
and the output would be
{ "names" : { "match" : "John Doe", "idx" : 0, "captures" : [ "John", "Doe" ] } }

groovy list indexOf

If I have a list with following elements
list[0] = "blach blah blah"
list[1] = "SELECT something"
list[2] = "some more text"
list[3] = "some more text"
How can I find the index of where the string starts with SELECT.
I can do list.indexOf("SELECT something");
But this is a dynamic list. SELECT something wont always be SELECT something. it could be SELECT somethingelse or anything but first word will always be SELECT.
Is there a way to apply regex to the indexOf search?
def list = ["blach blah blah", "SELECT something", "some more text", "some more text"]
def index = list.findIndexOf { it ==~ /SELECT \w+/ }
This will return the index of the first item that matches the regex /SELECT \w+/. If you want to obtain the indices of all matching items replace the second line with
def index = list.findIndexValues { it ==~ /SELECT \w+/ }
You can use a regex in find:
def list = ["blach blah blah", "SELECT something", "some more text", "some more text"]
def item = list.find { it ==~ /SELECT \w+/ }
assert item == "SELECT something"
list[1] = "SELECT somethingelse"
item = list.find { it ==~ /SELECT \w+/ }
assert item == "SELECT somethingelse"