Regex, aby uzyskać ciąg między nawiasami klamrowymi


115

Niestety, pomimo tego, że próbowałem nauczyć się regexów przynajmniej raz w roku przez tyle lat, ile pamiętam, zawsze zapominam, ponieważ używam ich tak rzadko. W tym roku moim noworocznym postanowieniem jest nie próbować ponownie uczyć się regex - więc w tym roku, aby uchronić mnie przed łzami, przekażę to Stack Overflow . (Remiks na ostatnie święta).

Chcę przekazać ciąg w tym formacie {getThis}i otrzymać ciąg getThis. Czy ktoś mógłby pomóc w dotrzymaniu mojego postanowienia noworocznego?


Powiązane pytania dotyczące przepełnienia stosu:


5
To pytanie zostało dodane do często zadawanych pytań dotyczących wyrażeń regularnych przepełnienia stosu , w sekcji „Zaawansowane wyrażenie regularne ”.
aliteralmind,

@Kobi: FAQ to wiki. Każdy może go edytować. Więc edytuj to.
aliteralmind

Odpowiedzi:


44

Jeśli twój ciąg zawsze będzie w tym formacie, wyrażenie regularne jest przesadą:

>>> var g='{getThis}';
>>> g.substring(1,g.length-1)
"getThis"

substring(1oznacza rozpoczęcie jednego znaku (tuż za pierwszym {) i ,g.length-1)oznacza zabranie znaków do (ale bez uwzględnienia) znaku o długości łańcucha minus jeden. To działa, ponieważ pozycja jest liczona od zera, tj. g.length-1Jest ostatnią pozycją.

Dla czytelników innych niż oryginalny plakat: jeśli ma to być wyrażenie regularne, użyj, /{([^}]*)}/jeśli chcesz zezwolić na puste ciągi lub /{([^}]+)}/jeśli chcesz dopasować tylko wtedy, gdy między nawiasami klamrowymi znajduje się co najmniej jeden znak. Awaria:

  • /: uruchom wzorzec wyrażenia regularnego
    • {: dosłowny nawias klamrowy
      • (: rozpocznij przechwytywanie
        • [: zacznij definiować klasę znaków do przechwycenia
          • ^}: „cokolwiek innego niż }
        • ]: OK, to cała nasza definicja klasy
        • *: dowolna liczba znaków pasujących do właśnie zdefiniowanej klasy
      • ): gotowe przechwytywanie
    • }: dosłowny nawias klamrowy musi natychmiast następować po tym, co uchwyciliśmy
  • /: kończy wzorzec wyrażenia regularnego

7
Podłańcuch to jedna z tych rzeczy, która zmienia się w zależności od języka, w którym pracujesz. Javascript zatrzymuje indeks, a PHP przyjmuje długość żądanego wyniku końcowego (chyba że jest ujemny, w takim przypadku potrzeba liczby znaków do usunięcia) , C # znowu jest inny ... ładny i zagmatwany.
jvenema

2
... a Python ma tylko wycinanie, które IMO jest lepsze niż cokolwiek innego: s.
Grant Paul

27
Świetnie, ale nie wiem, jak to jest wyrażenie regularne. Być może prosił o wyrażenie regularne, a ja przyszedłem tutaj po tę samą odpowiedź… niestety odpowiedź nie ma nic wspólnego z pytaniem ..
baash05

5
@ baash05, jeśli przeczytałeś całe pytanie, OP nie chciał nawet uczyć się wyrażeń regularnych, więc nie sądzę, że jest to ćwiczenie akademickie, które sugerujesz.
Kev,

2
Chciałem zrobić -1, ponieważ pytanie dotyczy wyrażenia regularnego , szukałem wyrażenia regularnego , ale zaakceptowana odpowiedź była dla mnie całkowicie bezużyteczna (podczas gdy pytanie samo w sobie wydawało się bardzo obiecujące). Po przeczytaniu pierwszego komentarza muszę przyznać, że gdybym miał najpierw odpowiedzieć na to pytanie, mógłbym odpowiedzieć w ten sam / podobny sposób ... Więc ostatecznie +1.
shadyyx

250

Próbować

/{(.*?)}/

Oznacza to, że dopasuj dowolny znak między {i}, ale nie bądź chciwy - dopasuj najkrótszy ciąg kończący się na} (znak? Przestaje * być chciwy). Nawiasy pozwalają wyodrębnić dopasowaną część.

Byłby inny sposób

/{([^}]*)}/

To pasuje do każdego znaku z wyjątkiem} char (inny sposób, aby nie być chciwym)


to jest świetne, ale czy można dopasować coś pomiędzy zmienną liczbą kombinacji nawiasów klamrowych? Np .: „{to powinno być dopasowane} to nie powinno {to jeszcze raz powinno} i tak {on}”? Chciałbym pobrać wartość, której nie ma w nawiasach klamrowych. Ponadto: w zdaniu nie będą używane nawiasy klamrowe i nie będzie można ich stosować (to nigdy by się nie zdarzyło: „{jakiś {tekst}}”). Ma ktoś pomysł jak to zrobić :)? Dzięki! (ps: głosował za tym rozwiązaniem)
Igor

4
Nie przechwytuje wszystkiego między nawiasami klamrowymi, ale wszystko, co znajduje się między nawiasami klamrowymi ORAZ same nawiasy klamrowe. Jak zabrałbyś się TYLKO do wychwytywania tego, co jest w nawiasach klamrowych?
Reality-Torrent

1
Podoba mi się, że nie musisz tu uciekać przed nawiasami klamrowymi, ponieważ parser wyrażeń regularnych zdaje się zdawać sobie sprawę, że nie są one kwantyfikatorem ... cóż, robię to w Pythonie, ale zakładam, że wyrażenia regularne javascript działają w ten sposób też
drevicko

3
Dodanie gna końcu powoduje, że jest to wyszukiwanie globalne. Zobacz działający przykład
Benjamin,

1
@ Reality-Torrent, też widziałem, że przechwycił nawiasy klamrowe, jeśli określę opcję g, aby uzyskać wszystkie dopasowania. Okazuje się, że powinienem użyć Regex.exec w pętli zamiast string.match w Javascript, aby mieć zarówno flagę g, jak i pozwolić na przechwytywanie grupy. Zobacz developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
frank

150
/\{([^}]+)\}/

/        - delimiter
\{       - opening literal brace escaped because it is a special character used for quantifiers eg {2,3}
(        - start capturing
[^}]     - character class consisting of
    ^    - not
    }    - a closing brace (no escaping necessary because special characters in a character class are different)
+        - one or more of the character class
)        - end capturing
\}       - the closing literal brace
/        - delimiter

@meouw sa = s.split ("/ \ {([^}] +) \} /"); daje błąd kompilacji. niedozwolone powtórzenie, nieprawidłowy znak ucieczki.
likejudo

@Wygląda na to, że jako argumentu podziału używasz ciągu znaków zamiast wyrażenia regularnego. Co próbujesz zrobić?
meouw

30

Spróbuj tego:

/[^{\}]+(?=})/g

Na przykład

Welcome to RegExr v2.1 by #{gskinner.com},  #{ssd.sd} hosted by Media Temple!

powróci gskinner.com, ssd.sd.


1
Świetnie, czy możesz wyjaśnić, dlaczego używasz \}w pierwszym bloku?
Uzair Ali

1
Niezły, ale będzie pasował do każdej grupy, która kończy się na }, nawet jeśli nie zaczyna się na {.
Ahmad Ibrahim

1
To jedyna poprawna odpowiedź, która faktycznie działa.
pldg

Objaśnienie: Podczas gdy [^ \ {\}] + będzie pasować do wszystkiego, co nie jest nawiasem klamrowym, asercja lookahead (? =}) Zapewni tylko przekazywanie sekcji poprzedzających nawias klamrowy. Za pomocą / ... / g otrzymujemy wszystkie wystąpienia, nie tylko pierwsze.
0 -_- 0

19

Oto proste rozwiązanie wykorzystujące zamianę javascript

var st = '{getThis}';

st = st.replace(/\{|\}/gi,''); // "getThis"

Jak wskazuje zaakceptowana odpowiedź powyżej, pierwotny problem można łatwo rozwiązać za pomocą podciągu, ale użycie zamiany może rozwiązać bardziej skomplikowane przypadki użycia

Jeśli masz ciąg typu „randomstring999 [nazwa pola]”, używasz nieco innego wzorca, aby uzyskać nazwę pola

var nameAttr = "randomstring999[fieldname]";

var justName = nameAttr.replace(/.*\[|\]/gi,''); // "fieldname"

15

Ten działa w Textmate i pasuje do wszystkiego w pliku CSS między nawiasami klamrowymi.

\{(\s*?.*?)*?\}

selector {. . matches here including white space. . .}

Jeśli chcesz mieć możliwość zwrócenia zawartości, zawiń ją w jeszcze jeden zestaw nawiasów, jak na przykład:

\{((\s*?.*?)*?)\}

i możesz uzyskać dostęp do zawartości za pośrednictwem $ 1.

Działa to również w przypadku funkcji, ale nie testowałem tego z zagnieżdżonymi nawiasami klamrowymi.


14

Chcesz używać wyrażeń regularnych lookahead i lookbehind. To da ci tylko to, co jest w nawiasach klamrowych:

(?<=\{)(.*?)(?=\})

Przed nawiasami klamrowymi powyżej powinien znajdować się ukośnik odwrotny. Zostały rozebrane w mojej opinii.
Robert Cesaric

1
Dzięki, pomogło mi to dzisiaj.
ProfessionalAmateur

jakieś wady tej metody?
Somatik

5
@ Somatik - tak, negatywne antycypowanie i wstecz nie są obsługiwane w ECMAScript.
RobG

Uwaga: ten przykład działa w Javie. Zwraca wszystkie wartości we wszystkich nawiasach klamrowych.
Multipleksor

13

Spróbuj tego

let path = "/{id}/{name}/{age}";
const paramsPattern = /[^{\}]+(?=})/g;
let extractParams = path.match(paramsPattern);
console.log("extractParams", extractParams) // prints all the names between {} = ["id", "name", "age"]

1
Dokładnie to, czego chciałem :) to zwróci wynik bez szelek, inne rozwiązania wrócą z nim
Al-Mothafar

Doskonała, najlepsza odpowiedź tutaj.
michal.jakubeczy

4

Regex do pobierania tablic ciągów z nawiasami klamrowymi występuje w ciągu znaków, a nie tylko do znajdowania pierwszego wystąpienia.

 /\{([^}]+)\}/gm 

4

przyjrzałem się innym odpowiedziom i wydaje się, że brakuje w nich istotnej logiki. tzn. zaznacz wszystko pomiędzy dwoma KOLEJNYMI nawiasami, ale NIE nawiasy

więc oto moja odpowiedź

\{([^{}]+)\}

3
var re = /{(.*)}/;
var m = "{helloworld}".match(re);
if (m != null)
    console.log(m[0].replace(re, '$1'));

Prościej .replace(/.*{(.*)}.*/, '$1')niestety zwraca cały ciąg, jeśli wyrażenie regularne nie pasuje. Powyższy fragment kodu może łatwiej wykryć dopasowanie.



2

Możesz użyć tej rekurencji wyrażenia regularnego, aby dopasować wszystko między, a nawet inne {}(np. Tekst JSON):

\{([^()]|())*\}

Fajnie, ale to przechwytuje zawartość tylko w zagnieżdżonych nawiasach klamrowych
Dominic

nie przechwytuje, jeśli treść zawiera ()
Mert Mertce

1

Nawet to pomaga mi w rozwiązywaniu czyjegoś problemu,

Podzielić zawartość wewnątrz nawiasów klamrowych ( {}) posiadający wzór podobnego {'day': 1, 'count': 100}.

Na przykład:

#include <iostream> 
#include <regex> 
#include<string> 
using namespace std; 

int main() 
{ 
    //string to be searched
    string s = "{'day': 1, 'count': 100}, {'day': 2, 'count': 100}";

    // regex expression for pattern to be searched 
    regex e ("\\{[a-z':, 0-9]+\\}");
    regex_token_iterator<string::iterator> rend;

    regex_token_iterator<string::iterator> a ( s.begin(), s.end(), e );
    while (a!=rend) cout << " [" << *a++ << "]";
    cout << endl;

    return 0; 
}

Wynik:

[{'day': 1, 'count': 100}] [{'day': 2, 'count': 100}]
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.