J
1. Analysis of your attemptsFor negative digits I have done this:/[(?:-\d)]/g
[(?:-\d)] the only thing he does is to match one character, which can be (, ?, :, one digit (\d), or ). When you use brackets, you're specifying a character class. That means it matches 1 and only 1 character within which they are declared.Intuitively, I tried to do this:/(^(?:-\d))/g
A ^ It serves to deny a class of characters, but only when it is within a class of characters, nothing more. When it is outside, in the pattern, it has a completely different meaning. ^ coincides with the position of the beginning of the text. It's no use denying anything, and denying with regular expressions is not something that gets so direct. Nothing more, with the position at the beginning of the text.2. About the expressions you foundI saw in another question, an answer that was:^(?!.*-\d).*$
It really works, but why should it be like that?(?!patrón) is a negative inspection (negative lookahead). What it does is to give a "spy" forward. The current position is fixed is not followed by a text that matches the pattern.But it has the particularity that it does not consume characters. After attempting the inspection, the cursor is still in the position he was in before. And the text with which it could match, is not part of the text fragment with which the regular expression is in its entirety.Being an inspection negativeIt makes the entire regex match if the inspection pattern doesn't match. That is: that the current position is not followed by something.^(?!.*-\d) matches the initial position, and it is fixed that position Don't be followed.:.* any number of characters (except line jumps)-\d one less and one digit.I mean, he's running the whole line looking for there's no one. -\d. Only if there were none, is that the rest of the regex pattern can keep trying to match.Then, .* matches the whole line.Basically, the entire string is going 2 times: 1 with the negative inspection, and the other with the .* principal (only if the inspection did not cause the global coincidence to fail).That way, it was guaranteed that there was no negative number. Only if it doesn't match is that the rest of the regex can still match the entire line.Besides, I saw that with this expression:^(?:(?!-\d).)+$
Why use a ^Until
where I understand that is for the beginning of the chainUse a ^ Just for that, to anchor it at the beginning of the text. If he wasn't there, he could match, for example:antes de un negativo -1 después de un negativo
^^^^^^^^^^^^^^^^^^^^^^^^
because from that position, there is nothing that is followed by a -\d. I mean, if I didn't have the ^, as it would not be anchored at the beginning, can match anywhere in the string, achieving a result that is not desired.Even without him ^I'd agree. 12345 in-12345
^^^^^
because from that position forward, there's nothing that's followed by a -\d. I mean, after passing the -There's nothing not followed by a less and a digit.Why use a captured group (?:)Otherwise, it's a non-capture group.That group not captured (?:(?!-\d).)+ serves to group the subpatron that is inside and be able to repeat everything with the + (1 or more times).I mean, it's gonna repeat (?!-\d).If it's not followed by a -\d,match 1 character.It's the same as a loop. It is traveling the character string by character, coinciding if and only if it is not followed by the start of a negative number. Source: https://regexper.com/#(%3F%3A(%3F!-%5Cd).)%2B Eye: These two expressions are not "mark"the rest of the text that is not a negative. What they do is verify that in the entire string there is no negative and, if not, they match the entire line.Ojo2: All these would fail with the number. -.5.^(?:(?!-\d).)+$ It's faster, but why would it be?Is it faster? Yes for some simple cases, but not necessarily for any case. Like everything in regex, it depends on the text to be compared. For example, I put this example in https://jsperf.com/lookahead-inicial-vs-lookahead-en-loop/1 where ^(?!.*-\d).*$ (with the initial lookahead) is evaluated faster (1.15% in the 1.2 million executions per second in what I tried recently).However, it is to be hoped that it will be the case for texts where the sign - is as the first character of the text. Why? Because the regex with the lookahead in a loop tries to find the - in the first character before following.^(?:(?!-\d).)+$ First, and only if it's not followed by -\dTry to match the first character. That's why I would fail in the first step with texts like -123in which he - makes him fail immediately.^(?!.*-\d).*$ instead, first try to sweep the whole line with .* and then he goes backtracking character by character (from the end to the beginning), trying to match -\d. That's why in the example of JSPerf, it has a better performance with text where the - is closer to the end of the line.But it also depends a lot on the language you're in. Each language has its own regex dialect, with a completely different engine. And JavaScript is, by far, within commonly used languages, the one that has the worst engine of regular expressions. This result may not be so in other languages (but equally, it always depends on the text with which you compare it). Each regular expression engine has its set of optimizations. And every optimization what you're looking for is to make an expression that won't match fail as soon as possible. For example, Perl has the most amazing optimizations, making many times that an expression will fail, not even enter the regex engine code to try, failing before.If you're really looking for an expression that collects character by character seeing that it's not followed by a pattern, there's a technique called unrolling the loop that has much better performance than the previous ones. This case, taken to a unrolling the loop It would be:^[^-]*(?:-(?!\d)[^-]*)*$
And, to prove it, a new JSPerf in https://jsperf.com/lookahead-inicial-vs-en-loop-vs-unrolling-the-loop/1 In Chrome 61, he gave meLookahead inicial 444,977
/^(?!.*-\d).*$/ ±3.40%
60% más lento
Lookahead en loop 801,615
/^(?:(?!-\d).)+$/ ±4.00%
29% más lento
Unrolling the loop 1,112,335
/^[^-](?:-(?!\d)[^-])*$/ ±2.24%
el más rápido
But again, this is from theory and adjusted to texts with generic cases. For each text, there will be one that behaves better than the other. And for every engine, you will have a different set of optimizations.3. How to see if a number is not negativeForget Regex! He uses his own language.if (numero < 0) {
console.log('Te aseguro que es muchísimo más rápido que con regex');
}
4. Just to learn, how would it be with regex?The best way is not to deny a pattern, but to deny the result of a regular expression. If you're interested in seeing that there's no negative in the text, we're looking to match it. -\dAnd then we deny the result:if ( ! /-\d/.test(texto) ) {
// Ok, no tiene números negativos
}
Or, if you're interested in deleting them from the text, we're looking to match the negatives (I present it with decimals andity exponent):/-\d+(?:.\d+)?(?:e[-+]?\d+)?/gi
And we replaced them with "" to remove them.textoSinNegativos = texto.replace(/-\d+(?:.\d+)?(?:e[-+]?\d+)?/gi, '');
input is any character, and it would be marked any character that is not a negative digitIf the idea is to separate each of the fragments that are not negative numbers, we would use split() to get each part separately.> 'abcd -123 def'.split(/-\d+(?:.\d+)?(?:e[-+]?\d+)?/gi)
< ["abcd ", " def"]