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:

ChrisInCambo
źródło
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
Kev
źródło
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)

Paul Dixon
źródło
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
źródło
@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.

Mohamed Abo Elmagd
źródło
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"
chim
źródło
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.

Alex Kessaris
źródło
14

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

(?<=\{)(.*?)(?=\})
Robert Cesaric
źródło
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"]
Hemadri Dasari
źródło
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 
Er. Mohit Agrawal
źródło
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ź

\{([^{}]+)\}
souparno majumder
źródło
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.

Curtis Yallop
źródło
3

Spróbuj tego, zgodnie z http://www.regextester.com działa normalnie dla js .

([^{]*?)(?=\})

Павло Коменда
źródło
3
do wielokrotnego wyboru możesz użyć /([^{]*?)\w(?=\})/gmi
Павло Коменда
2

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

\{([^()]|())*\}
p3quod
źródło
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}]
Shudipta Sharma
źródło