2013-03-28 6 views
9

Chciałbym zamienić wszystkie ciągi, które są ujęte w - na ciągi znaków dołączone przez ~, ale nie, jeśli ten ciąg ponownie jest zawarty w *.Nie zastępuj wyrażenia regularnego, jeśli jest ono zamknięte znakiem

Jako przykład tego ciągu ...

The -quick- *brown -f-ox* jumps. 

... powinien stać ...

The ~quick~ *brown -f-ox* jumps. 

Widzimy - otrzymuje tylko jeśli jest nie ciągu *<here>*.

Moje javascript regex teraz (co trwa nie obchodzi, czy jest on zamknięty przez * lub nie):

var message = source.replace(/-(.[^-]+?)-/g, "~$1~"); 

EDIT: Należy pamiętać, że to może być tak, że jest nieparzysta liczba * s .

+7

Dlaczego spadamy? – poitroae

+0

Tak, jestem zdziwiony, takie dobre pytanie. – Jai

+2

Co w przypadku nieparzystej liczby znaków *? Na przykład. '* -szybki- * brązowy * -f-ox * przeskakuje * .' Które znaki' -' powinny zostać zastąpione i dlaczego? –

Odpowiedz

2

To jest trochę skomplikowana sprawa z wyrażeń regularnych. Myślę, co bym zrobił coś takiego:

var msg = source.replace(/(-[^-]+-|\*[^*]+\*)/g, function(_, grp) { 
    return grp[0] === '-' ? grp.replace(/^-(.*)-$/, "~$1~") : grp; 
}); 

jsFiddle Demo

To wygląda na albo*- lub grupy, a jedynie dokonuje wymiany na tych przerywanych. Ogólnie mówiąc, składnia "zagnieżdżania" jest wyzwaniem (lub niemożliwym) przy użyciu wyrażeń regularnych. (I oczywiście jako komentarz w uwagach pytanie istnieją szczególne przypadki — wiszące metaznakami — które komplikują to zbyt.)

+1

Przykład roboczy: http://jsfiddle.net/Zb6BU/ - nie wiesz, dlaczego to nie jest podnoszenie głosów, działa to tak, jak powinno! +1 –

+0

@mcpDESIGNS: Inne odpowiedzi również działają :-) – Bergi

+0

@Bergi Widzę to teraz, + 1's dla wszystkich :) haha ​​ –

1

chciałbym go rozwiązać poprzez podział w oparciu o tablicę * a następnie zastąpienie tylko parzyste indeksów. Dopasowane niesymetryczne gwiazdki, jest to trudniejsze, to wymaga wiedząc, czy indeks ostatniego elementu jest parzysty, czy nieparzysty:

'The -quick- *brown -f-ox* jumps.' 
    .split('*') 
    .map(function(item, index, arr) { 
     if (index % 2) { 
      if (index < arr.length - 1) { 
       return item; // balanced 
      } 
      // not balanced 
      item = '*' + item; 
     } 
     return item.replace(/\-([^-]+)\-/, '~$1~'); 
    }) 
    .join(''); 

Demo

+0

Co jeśli łańcuch zawiera znak "*", który nie jest częścią pary? na przykład '' Szybki-* brązowy -f-ox przeskakuje. 'Jeśli dobrze rozumiem, w tym przypadku oba' -quick-'i' -f-'powinny zostać zastąpione, ale tylko' -quick-'. –

+0

@KenB Zakłada się, że gwiazdy są dobrze zrównoważone :) –

+0

W zależności od kontekstu, jest to dość duże założenie. –

1

Dowiedzieć się, czy mecz jest nie zamknięty przez niektórych ograniczników jest to bardzo skomplikowane zadanie - patrz także this example. Lookaround może pomóc, ale JS obsługuje tylko wyświetlanie z wyprzedzeniem. Więc możemy przepisać „nie otoczony ~” do „następnie parzystej liczby lub ~”, a mecz na tym:

source.replace(/-([^-]+)-(?=[^~]*([^~]*~[^~]*~)*$)/g, "~$1~"); 

Ale lepiej możemy dopasować zarówno - i *, abyśmy konsumować wszystko zawinięte w * s, jak również i może wtedy zdecydować, w funkcji wywołania zwrotnego nie do zastąpienia go:

source.replace(/-([^-]+)-|\*([^*]+)\*/g, function(m, hyp) { 
    if (hyp) // the first group has matched 
     return "~"+hyp+"~"; 
    // else let the match be unchanged: 
    return m; 
}); 

ma to tę zaletę, że jest w stanie lepiej określić "załączony", np.dodając granice słów na "środku", dla lepszej obsługi nieprawidłowych wzorców (nieparzysta liczba * znaków, jak wspomina na przykład @Maras) - obecne wyrażenie regularne zajmuje tylko dwa następne wystąpienia.

0

Ostra wersja bardzo jasnej odpowiedzi Jacka.

source.split(/(\*[^*]*\*)/g).map(function(x,i){ 
return i%2?x:x.replace(/-/g,'~'); 
}).join(''); 

Wydaje się pracować, Pozdrawiam.

Powiązane problemy