The @LeAndrade answer explains very well how to solve the problem. I would just like to add an explanation about your attempt (because it did not work), as well as propose some alternatives.
Uncrossing the expression you used ( ^[:.:]$
):
-
^
and $
mean, respectively, the beginning and end of the string
- brackets (
[]
) delimit a class (or set) of characters , which causes the expression matches match with an occurrence of any character inside the brackets.
For example, [ab]
means: the letter "a"
or the letter "b"
. If I want the letter "a" followed by the letter "b", I have to remove them from the brackets.
Thus, [:.:]
means: the character ":"
or the character "."
or the character ":"
(that is, the colon is redundant). Depending on the regex engine being used, this can give error (some do not allow repeated characters inside the brackets and give error, since this is redundant).
Another detail is that the dot ( .
) inside the brackets loses its special meaning of "any character" and becomes only the "dot" itself.
In short, the expression ^[:.:]$
means "string that only has an instance of :
or .
". Since you have used ^
and $
to indicate the beginning and end of the string, the expression only matches to single-character strings.
Alternatives to the solution
The #LeAndrade solution seems to be what you need. But if you want to refine the expression a bit, you can change it according to your use cases.
If :
can only have numbers, I suggest changing .
to \d
or [0-9]
(expressions that matches any digit from 0 to 9 ). Both of the following expressions do this:
:(\d+):
:([0-9]+):
I also changed the quantifier *
(zero or more occurrences) to +
(one or more occurrences). By using *
, there is the risk of accidentally doing match with ::
. Using +
, ensures that there must be at least one digit.
If you can have numbers or letters, an alternative is to use the brackets by putting these characters in. As we saw in the previous example, it is possible to define ranges of characters with the hyphen, then the expression would be:
// letras maiúsculas, minúsculas, ou dígitos de 0 a 9
:([A-Za-z0-9]+):
If you can have anything between :
, an alternative is to use a denied character class: you can put ^
inside brackets, and then it will < > match with any character not within them.
In this case, I'd do [^:]
, which means "any character other than :
". The expression would look like this:
:([^:]+):
That is, "colon, followed by one or more occurrences of any character other than colon, followed by colon."
Of course you can use .*?
as already suggested. I would only change to .+?
to ensure that there is at least one character between :
.
But if you already know the possible values (just numbers, or letters and numbers, or any other rule) I suggest using a narrower expression than .*
to avoid false positives.
And since you mentioned that you need to get the positions where the characters appear, an alternative is to use property lastIndex
of object RegExp
, which stores the position from which the next occurrence will be searched.
That is, at each iteration of the loop, lastIndex
is updated to the position of the match string position. If I want to know the position where the occurrence begins, just subtract the match size itself:
let texto = "teste :1: e também teste :2:";
let regex = new RegExp(':([^:]+):', 'g');
let result;
while ((result = regex.exec(texto))) {
console.log("Encontrado entre os : -> " + result[1]);
// subtrair tamanho do match para obter a posição em que começa
console.log("Posição inicial do : -> " + (regex.lastIndex - result[0].length));
}