lookarounds positive negative lookbehind lookahead - vsvim

after searching all over google for vsvim lookahead or lookbehind and on the wiki I can't seem to figure out how, or if it even supports lookahead or lookbehind (positives or negatives) and how to use them if so.
I've tried a few different syntaxes like \ze \#= (?<=let \w\+)( \(?<=let \w\+\)( that I've seen on vim answers but none of them seem to be working in vs vim for matching (nor substitution)
how do you do lookarounds in VsVim?

For any newcomers, I'll copy the contents of this link here for the future:
http://ssiaf.blogspot.ru/2009/07/negative-lookbehind-in-vim.html
/\(Start\)\#<!Date
This will match the 'Date' in 'EndDate' and 'YesterdaysDate' but will not match 'StartDate'
/Start\(Date\)\#!
will match the 'Start' in 'Starting but not in 'StartDate'
/Start\(Date\)\#=
will match the 'Start' in 'StartDate' but not in 'Starting
/\(Start\)\#<=Date
will match the 'Date' in 'StartDate' but not in 'EndDate' and 'YesterdaysDate'

I want to expand on the excellent answer from #briansrls. I was looking for a more robust solution that could handle multi-word phrases, wildcards (for potential gaps between phrases) and alternatives (i.e., patterns):
Without wildcards:
Positive Lookahead: \(find this\)\(followed by this\|or that\)\#=
Negative Lookahead: \(find this\)\(not followed by this\|or that\)\#!
Positive Lookbehind: \(preceded by this\|or that\)\#<=\(find this\)
Negative Lookbehind: \(not preceded by this\|or that\)\#<!\(find this\)
With wildcards:
Positive lookahead: \(find this\)\(.*\(eventually followed by this\|or that\)\)\#=
Negative lookahead: \(find this\)\(.*\(not eventually followed by this:\|or that\)\)\#!
Positive lookbehind: \(\(eventually preceded by this\|or that\).*\)\#<=\(find this\)
Negative lookbehind: \(\(not eventually preceded by this\|or that\).*\)\#<!\(find this\)
Note: For the wildcard versions, the extra parentheses are required so that the wildcard is excluded from the alternatives group, but is included in the lookaround group. This prevents duplicating the wildcards for every alternative. One could also use \zs & \ze to avoid the extra parentheses, but I find this method slightly more intuitive.
For more information:
Basic: https://www.cheatography.com/fievel/cheat-sheets/vim-regexp/
Advanced: http://vimdoc.sourceforge.net/htmldoc/pattern.html
Update: It appears that \zs & \ze are not yet implemented in VsVim as of this time.

Related

Snowflake and Regular Expressions - issue when implementing known good expression in SF

I'm looking for some assistance in debugging a REGEXP_REPLACE() statement.
I have been using an online regular expressions editor to build expressions, and then the SF regexp_* functions to implement them. I've attempted to remain consistent with the SF regex implementation, but I'm seeing an inconsistency in the returned results that I'm hoping someone can explain :)
My intent is to replace commas within the text (excluding commas with double-quoted text) with a new delimiter (#^#).
Sample text string:
"Foreign Corporate Name Registration","99999","Valuation Research",,"Active Name",02/09/2020,"02/09/2020","NEVADA","UNITED STATES",,,"123 SOME STREET",,"MILWAUKEE","WI","53202","UNITED STATES","123 SOME STREET",,"MILWAUKEE","WI","53202","UNITED STATES",,,,,,,,,,,,
RegEx command and Substitution (working in regex101.com):
([("].*?["])*?(,)
\1#^#
regex101.com Result:
"Foreign Corporate Name Registration"#^#"99999"#^#"Valuation Research"#^##^#"Active Name"#^#02/09/2020#^#"02/09/2020"#^#"NEVADA"#^#"UNITED STATES"#^##^##^#"123 SOME STREET"#^##^#"MILWAUKEE"#^#"WI"#^#"53202"#^#"UNITED STATES"#^#"123 SOME STREET"#^##^#"MILWAUKEE"#^#"WI"#^#"53202"#^#"UNITED STATES"#^##^##^##^##^##^##^##^##^##^##^##^#
When I try and implement this same logic in SF using REGEXP_REPLACE(), I am using the following statement:
SELECT TOP 500
A.C1
,REGEXP_REPLACE((A."C1"),'([("].*?["])*?(,)','\\1#^#') AS BASE
FROM
"<Warehouse>"."<database>"."<table>" AS A
This statement returns the result for BASE:
"Foreign Corporate Name Registration","99999","Valuation Research",,"Active Name",02/09/2020,"02/09/2020","NEVADA","UNITED STATES",,,"123 SOME STREET",,"MILWAUKEE","WI","53202","UNITED STATES","123 SOME STREET",,"MILWAUKEE","WI","53202","UNITED STATES"#^##^##^##^##^##^##^##^##^##^##^##^#
As you can see when comparing the results, the SF result set is only replacing commas at the tail-end of the text.
Can anyone tell me why the results between regex101.com and SF are returning different results with the same statement? Is my expression non-compliant with the SF implementation of RegEx - and if yes, can you tell me why?
Many many thanks for your time and effort reading this far!
Happy Wednesday,
Casey.
The use of .*? to achieve lazy matching for regexing is limited to PCRE, which Snowflake does not support. To see this, in regex101.com, change your 'flavor" to be anything other than PCRE (PHP); you will see that your ([("].*?["])*?(,) regex no longer achieves what you are expecting.
I believe that this will work for your purposes:
REGEXP_REPLACE(A.C1,'("[^"]*")*,','\\1#^#')

Regular expression to check multiple phone number with and without extensions

In my angular application, I've a text field to get phone number from user.
User can enter multiple phone numbers
separated by comma (Without country code and omitting 0 of city code)
For example if the phone number is 042-1234567, User will enter 421234567 and multiple numbers will be like
421234567,421234568,...
This regular expression working perfectly fine for me
^((\d{9})(,\d{9})*)$
But there's exception that user can also add extensions with phone number like this
123456786~19, 123456784~46,..
I've tried following Regx and its working fine for these kind of inputs
^((\d{9}~\d{2})(,\d{9}~\d{2})*)$
But I've to use both of these in one single field so I tried to add OR option and made Regx like this
((\d{9}~\d{2})(,\d{9}~\d{2})*)|((\d{9})(,\d{9})*)
But its not working for both kind of inputs. e.g;
Its not validating this 123456789~12,123456789~12,123456789,123456789~12
Any kind of help will be appreciated.
You may use optional groups:
^\d{9}(?:~\d{2})?(?:,\d{9}(?:~\d{2})?)*$
^^^^^^^^^^^ ^^^^^^^^^^^
See the regex demo
Details
^ - start of string
\d{9} - any 9 digits
(?:~\d{2})? - an optional non-capturing group matching
~ - a tilde
\d{2} - any 2 digits
(?:,\d{9}(?:~\d{2})?)* - zero or more sequences of:
, - a comma
\d{9}(?:~\d{2})? - see above
$ - end of string.
Note that if you need the pattern to also match an empty string, just enclose the pattern with an optional non-capturing group, ^(?:\d{9}(?:~\d{2})?(?:,\d{9}(?:~\d{2})?)*)?$.

Regex for US Zip code - but make it optional

I need a regex for US zip codes. I've found lots of examples but none that allow for the zip code to also be optional. You see, I am using this on a non-required input field so the valid scenarios are a 5 digit zip code, a 5+4 digit zip code, or no zip code at all. Here is what I have so far but it does not work for the "no zip code at all" scenario:
^(\d{5}(?:\-\d{4})?)$
You need to enclose the whole pattern with a non-capturing optional group:
^(?:\d{5}(?:-\d{4})?)?$
^^^ ^^
See the regex demo
Details:
^ - start of string
(?: - start of the optional group
\d{5} - 5 digits
(?:-\d{4})? - optional group matching - and 4 digits
)? - end of the outer optional group
$ - end of string.
Note that it is the ? quantifier that makes the outer non-capturing group optional (match 1 or 0 times).
You might as well use capturing groups if you want to make your pattern shorter, but it a non-capturing one is more natural to use here since you are not interested in captured subvalues.

Regular Expression in Visual Studio Find & Replace - multiple spaces between search terms

I require a regular expression for the Visual Studio Search and Replace functionality, as follows:
Search for the following term: sectorkey in (
There could be multiple spaces between each of the above 3 search terms, or even multiple line breaks/carriage returns.
The search term is looking for SQL statements that have hard-coded SectorKey values inside a SQL in statement. These need to be replaced with a SQL join statement - this will be done manually.
The little arrow to the right of the Find What box is your friend and can help you with the vagaries of the MS regex syntax.
Newline is represented by \n, so you can just do sectorkey( |\n)+in( |\n)+\( (You need to escape the open paren in your search expression, since that's used in grouping.)
I believe :Wh+ is what you want. The Visual Studio regex flavor is very strange; you'll tend to get better results if you consult the official reference. Expertise with "mainstream" regexes tends to be more of a handicap than a help when it comes to VS.
You can use \s+ to search for one or more adjacent whitespace characters (including tab, CR, LF etc), so your regex would presumably end up looking something like sectorkey\s+in\s+\(.
Edit...
As Joe points out in his comment, it seems that Visual Studio doesn't support \s in Find/Replace expressions, in which case you'll probably need to use something like [\n:b] instead. The regex would then become sectorkey[\n:b]+in[\n:b]+\(.

How do you get leading wildcard full-text searches to work in SQL Server?

Note: I am using SQL's Full-text search capabilities, CONTAINS clauses and all - the * is the wildcard in full-text, % is for LIKE clauses only.
I've read in several places now that "leading wildcard" searches (e.g. using "*overflow" to match "stackoverflow") is not supported in MS SQL. I'm considering using a CLR function to add regex matching, but I'm curious to see what other solutions people might have.
More Info: You can add the asterisk only at the end of the word or phrase. - along with my empirical experience: When matching "myvalue", "my*" works, but "(asterisk)value" returns no match, when doing a query as simple as:
SELECT * FROM TABLENAME WHERE CONTAINS(TextColumn, '"*searchterm"');
Thus, my need for a workaround. I'm only using search in my site on an actual search page - so it needs to work basically the same way that Google works (in the eyes on a Joe Sixpack-type user). Not nearly as complicated, but this sort of match really shouldn't fail.
Workaround only for leading wildcard:
store the text reversed in a different field (or in materialised view)
create a full text index on this column
find the reversed text with an *
SELECT *
FROM TABLENAME
WHERE CONTAINS(TextColumnREV, '"mrethcraes*"');
Of course there are many drawbacks, just for quick workaround...
Not to mention CONTAINSTABLE...
The problem with leading Wildcards: They cannot be indexed, hence you're doing a full table scan.
It is possible to use the wildcard "*" at the end of the word or phrase (prefix search).
For example, this query will find all "datab", "database", "databases" ...
SELECT * FROM SomeTable WHERE CONTAINS(ColumnName, '"datab*"')
But, unforutnately, it is not possible to search with leading wildcard.
For example, this query will not find "database"
SELECT * FROM SomeTable WHERE CONTAINS(ColumnName, '"*abase"')
To perhaps add clarity to this thread, from my testing on 2008 R2, Franjo is correct above. When dealing with full text searching, at least when using the CONTAINS phrase, you cannot use a leading , only a trailing functionally. * is the wildcard, not % in full text.
Some have suggested that * is ignored. That does not seem to be the case, my results seem to show that the trailing * functionality does work. I think leading * are ignored by the engine.
My added problem however is that the same query, with a trailing *, that uses full text with wildcards worked relatively fast on 2005(20 seconds), and slowed to 12 minutes after migrating the db to 2008 R2. It seems at least one other user had similar results and he started a forum post which I added to... FREETEXT works fast still, but something "seems" to have changed with the way 2008 processes trailing * in CONTAINS. They give all sorts of warnings in the Upgrade Advisor that they "improved" FULL TEXT so your code may break, but unfortunately they do not give you any specific warnings about certain deprecated code etc. ...just a disclaimer that they changed it, use at your own risk.
http://social.msdn.microsoft.com/Forums/ar-SA/sqlsearch/thread/7e45b7e4-2061-4c89-af68-febd668f346c
Maybe, this is the closest MS hit related to these issues... http://msdn.microsoft.com/en-us/library/ms143709.aspx
One thing worth keeping in mind is that leading wildcard queries come at a significant performance premium, compared to other wildcard usages.
Note: this was the answer I submitted for the original version #1 of the question before the CONTAINS keyword was introduced in revision #2. It's still factually accurate.
The wildcard character in SQL Server is the % sign and it works just fine, leading, trailing or otherwise.
That said, if you're going to be doing any kind of serious full text searching then I'd consider utilising the Full Text Index capabilities. Using % and _ wild cards will cause your database to take a serious performance hit.
Just FYI, Google does not do any substring searches or truncation, right or left. They have a wildcard character * to find unknown words in a phrase, but not a word.
Google, along with most full-text search engines, sets up an inverted index based on the alphabetical order of words, with links to their source documents. Binary search is wicked fast, even for huge indexes. But it's really really hard to do a left-truncation in this case, because it loses the advantage of the index.
As a parameter in a stored procedure you can use it as:
ALTER procedure [dbo].[uspLkp_DrugProductSelectAllByName]
(
#PROPRIETARY_NAME varchar(10)
)
as
set nocount on
declare #PROPRIETARY_NAME2 varchar(10) = '"' + #PROPRIETARY_NAME + '*"'
select ldp.*, lkp.DRUG_PKG_ID
from Lkp_DrugProduct ldp
left outer join Lkp_DrugPackage lkp on ldp.DRUG_PROD_ID = lkp.DRUG_PROD_ID
where contains(ldp.PROPRIETARY_NAME, #PROPRIETARY_NAME2)
When it comes to full-text searching, for my money nothing beats Lucene. There is a .Net port available that is compatible with indexes created with the Java version.
There's a little work involved in that you have to create/maintain the indexes, but the search speed is fantastic and you can create all sorts of interesting queries. Even indexing speed is pretty good - we just completely rebuild our indexes once a day and don't worry about updating them.
As an example, this search functionality is powered by Lucene.Net.
Perhaps the following link will provide the final answer to this use of wildcards: Performing FTS Wildcard Searches.
Note the passage that states: "However, if you specify “Chain” or “Chain”, you will not get the expected result. The asterisk will be considered as a normal punctuation mark not a wildcard character. "
If you have access to the list of words of the full text search engine, you could do a 'like' search on this list and match the database with the words found, e.g. a table 'words' with following words:
pie
applepie
spies
cherrypie
dog
cat
To match all words containing 'pie' in this database on a fts table 'full_text' with field 'text':
to-match <- SELECT word FROM words WHERE word LIKE '%pie%'
matcher = ""
a = ""
foreach(m, to-match) {
matcher += a
matcher += m
a = " OR "
}
SELECT text FROM full_text WHERE text MATCH matcher
% Matches any number of characters
_ Matches a single character
I've never used Full-Text indexing but you can accomplish rather complex and fast search queries with simply using the build in T-SQL string functions.
From SQL Server Books Online:
To write full-text queries in
Microsoft SQL Server 2005, you must
learn how to use the CONTAINS and
FREETEXT Transact-SQL predicates, and
the CONTAINSTABLE and FREETEXTTABLE
rowset-valued functions.
That means all of the queries written above with the % and _ are not valid full text queries.
Here is a sample of what a query looks like when calling the CONTAINSTABLE function.
SELECT RANK , * FROM TableName ,
CONTAINSTABLE (TableName, *, '
"*WildCard" ') searchTable WHERE
[KEY] = TableName.pk ORDER BY
searchTable.RANK DESC
In order for the CONTAINSTABLE function to know that I'm using a wildcard search, I have to wrap it in double quotes. I can use the wildcard character * at the beginning or ending. There are a lot of other things you can do when you're building the search string for the CONTAINSTABLE function. You can search for a word near another word, search for inflectional words (drive = drives, drove, driving, and driven), and search for synonym of another word (metal can have synonyms such as aluminum and steel).
I just created a table, put a full text index on the table and did a couple of test searches and didn't have a problem, so wildcard searching works as intended.
[Update]
I see that you've updated your question and know that you need to use one of the functions.
You can still search with the wildcard at the beginning, but if the word is not a full word following the wildcard, you have to add another wildcard at the end.
Example: "*ildcar" will look for a single word as long as it ends with "ildcar".
Example: "*ildcar*" will look for a single word with "ildcar" in the middle, which means it will match "wildcard". [Just noticed that Markdown removed the wildcard characters from the beginning and ending of my quoted string here.]
[Update #2]
Dave Ward - Using a wildcard with one of the functions shouldn't be a huge perf hit. If I created a search string with just "*", it will not return all rows, in my test case, it returned 0 records.

Resources