Wyrażenie regularne dopasowujące wszystkie instancje Nie wewnątrz cudzysłowów

Z tego q/A wydedukowałem, że dopasowanie wszystkich wystąpień danego regex nie wewnątrz cudzysłowów jest niemożliwe. Oznacza to, że nie może pasować do cudzysłowów (np.: "this whole \"match\" should be taken"). Jeśli jest na to sposób, o którym Nie wiem, to rozwiąże mój problem.

Jeśli jednak nie, chciałbym wiedzieć, czy istnieje jakaś skuteczna alternatywa, która mogłaby być użyta w JavaScript. Trochę o tym myślałem, ale nie mogę znaleźć żadnych eleganckich rozwiązań, które sprawdziłyby się w większości, jeśli nie wszystkie, sprawy.

W szczególności potrzebuję alternatywy do pracy .split () i .metody replace (), ale gdyby mogły być bardziej uogólnione, to byłoby najlepiej.

Na Przykład:
Ciąg wejściowy:
+bar+baz"not+or\"+or+\"this+"foo+bar+
zastąpienie + przez#, nie wewnątrz cudzysłowów, zwróci:
#bar#baz"not+or\"+or+\"this+"foo#bar#

Author: Community, 2011-06-24

4 answers

Właściwie, można dopasować wszystkie instancje wyrażenia regularnego Nie wewnątrz cudzysłowów dla dowolnego ciągu znaków, gdzie każdy otwierający cudzysłów jest ponownie zamknięty. Powiedzmy, jak w powyższym przykładzie, chcesz dopasować \+.

Kluczową obserwacją jest to, że słowo jest poza cudzysłowami, Jeśli za nim znajduje się parzysta liczba cudzysłowów. Można to wymodelować jako twierdzenie typu look-ahead:

\+(?=([^"]*"[^"]*")*[^"]*$)
Nie licz cudzysłowów. To jest trochę bardziej skomplikowane. Zamiast [^"]*, które awansowały do następny cytat, musisz wziąć pod uwagę również ukośniki i użyć [^"\\]*. Po osiągnięciu ukośnika wstecznego lub cytatu, musisz zignorować następny znak, jeśli napotkasz ukośnik wsteczny, lub przejść do następnego unescaped cytat. To wygląda jak (\\.|"([^"\\]*\\.)*[^"\\]*"). Razem, docierasz do
\+(?=([^"\\]*(\\.|"([^"\\]*\\.)*[^"\\]*"))*[^"]*$)

Przyznaję, że to jest mały tajemniczy. =)

 109
Author: Jens,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-07-03 14:35:18

Azmisow, wskrzeszając to pytanie, ponieważ powiedziałeś, że szukasz any efficient alternative that could be used in JavaScript i any elegant solutions that would work in most, if not all, cases.

Zdarza się, że istnieje proste, ogólne rozwiązanie, o którym nie wspomniano.

W porównaniu z alternatywami, Wyrażenie regularne dla tego rozwiązania jest zadziwiająco proste:

"[^"]+"|(\+)

Chodzi o to, że dopasowujemy, ale ignorujemy cokolwiek w cudzysłowach, aby zneutralizować tę treść (po lewej stronie alternacji). Po prawej stronie chwytamy wszystkie +, które nie zostały zneutralizowane w Grupa 1, a funkcja replace bada grupę 1. Oto Pełny kod roboczy:

<script>
var subject = '+bar+baz"not+these+"foo+bar+';
var regex = /"[^"]+"|(\+)/g;
replaced = subject.replace(regex, function(m, group1) {
    if (!group1) return m;
    else return "#";
});
document.write(replaced);

Demo Online

Możesz użyć tej samej zasady, aby dopasować lub podzielić. Zobacz pytanie i artykuł w odnośniku, który również wskaże Ci próbki kodu.

Mam nadzieję, że to daje wam inne wyobrażenie o bardzo ogólnym sposobie, aby to zrobić. :)

A co z pustymi strunami?

Powyższe jest ogólną odpowiedzią na zaprezentowanie techniki. Informatyka można dostosować w zależności od konkretnych potrzeb. Jeśli obawiasz się, że Twój tekst może zawierać puste ciągi, po prostu zmień kwantyfikator wewnątrz wyrażenia string-capture z + na *:

"[^"]*"|(\+)

Zobacz demo .

A co z uciekającymi cytatami?

Ponownie, powyższe jest ogólną odpowiedzią na zaprezentowanie techniki. Wyrażenie regularne "ignore this match " może być dopracowane do Twoich potrzeb, możesz dodać wiele wyrażeń do zignorowania. Na na przykład, jeśli chcesz mieć pewność, że cudzysłowy unikalne są odpowiednio ignorowane, możesz zacząć od dodania alternacji \\"| przed dwoma pozostałymi w celu dopasowania (i zignorowania) marnotrawienia cudzysłowów unikalnych.

Następnie, w sekcji "[^"]*", która przechwytuje zawartość podwójnych cytatów, możesz dodać alternację, aby upewnić się, że unikalne podwójne cytaty są dopasowane, zanim ich " będzie miała szansę przekształcić się w wartownik zamykający, zamieniając go w "(?:\\"|[^"])*"

Wynik wyrażenie ma trzy gałęzie:

  1. \\" aby dopasować i zignorować
  2. "(?:\\"|[^"])*" dopasować i zignorować
  3. (\+) dopasować, uchwycić i uchwycić

Zauważ, że w innych odmianach regex, możemy wykonać tę pracę łatwiej z lookbehind, ale JS jej nie obsługuje.

Pełny regex staje się:

\\"|"(?:\\"|[^"])*"|(\+)

Zobacz demo regex I pełny skrypt .

Odniesienie

  1. jak dopasować wzór z wyjątkiem sytuacji s1, s2, S3
  2. jak dopasować wzór, chyba...
 61
Author: zx81,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 11:54:59

Możesz to zrobić w trzech krokach.

  1. Użyj regex global replace, aby wyodrębnić całą zawartość ciała do tabeli bocznej.
  2. wykonaj tłumaczenie przecinka
  3. Użyj regex global replace, aby zamienić ciała łańcuchów z powrotem

Kod poniżej

// Step 1
var sideTable = [];
myString = myString.replace(
    /"(?:[^"\\]|\\.)*"/g,
    function (_) {
      var index = sideTable.length;
      sideTable[index] = _;
      return '"' + index + '"';
    });
// Step 2, replace commas with newlines
myString = myString.replace(/,/g, "\n");
// Step 3, swap the string bodies back
myString = myString.replace(/"(\d+)"/g,
    function (_, index) {
      return sideTable[index];
    });

Jeśli uruchomisz to po ustawieniu

myString = '{:a "ab,cd, efg", :b "ab,def, egf,", :c "Conjecture"}';

Powinieneś dostać

{:a "ab,cd, efg"
 :b "ab,def, egf,"
 :c "Conjecture"}

To działa, ponieważ po kroku 1,

myString = '{:a "0", :b "1", :c "2"}'
sideTable = ["ab,cd, efg", "ab,def, egf,", "Conjecture"];

Więc jedyne przecinki w mystringu są poza łańcuchami. Krok 2, a następnie zamienia przecinki do newlines:

myString = '{:a "0"\n :b "1"\n :c "2"}'

Na koniec zamieniamy ciągi zawierające tylko liczby z ich oryginalną zawartością.

 6
Author: Mike Samuel,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-08-18 13:11:47

Chociaż odpowiedź zx81 wydaje się być najskuteczniejsza i najczystsza, potrzebne są te poprawki, aby poprawnie wyłapać unikalne cytaty:

var subject = '+bar+baz"not+or\\"+or+\\"this+"foo+bar+';

I

var regex = /"(?:[^"\\]|\\.)*"|(\+)/g;

Również wspomniane już "group1 = = = undefined "lub"!group1". Szczególnie 2. wydaje się ważne, aby właściwie wziąć pod uwagę wszystko zadane w pierwotnym pytaniu.

Należy jednak wspomnieć, że ta metoda domyślnie wymaga, aby łańcuch znaków nie miał unikalnych cudzysłowów poza unescaped quote pary.

 2
Author: Marius,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-10-25 16:34:44