Próbuję napisać regex, który sprawia, że następne rzeczy:

  1. _ - & gt; Wymień go przez przestrzeń
  2. + - & gt; Usuń go, jeśli nie jest inny + po tym (tj. c++ = & gt; c++. c+ - & gt; c)
  3. ' - & gt; Usuń go, jeśli jest na początku lub na końcu słowa (tj. Alin's - & gt; Alin's. 'Alin's - & gt; alin's)
  4. &, -, ., ! - Nie usuwaj.
  5. Kolejne znaki specjalne - usuń

Chcę to zrobić, przekazując jeden raz ciąg

Na przykład:

Input: "abc's, test_s! & c++ c+ 'Dirty's'. and beautiful'..."
Output: "abc's test s! & c++ c Dirty's. and beautiful..."

Wyjaśnienie:

char `'` in `abc's,` stays because `3`
char `,` in `abc's,` was removed because `5` 
char `_` in `test_s!` was replaced by space because `1`
char `!` in `test_s!` is not removed because `!`
char `&` is not removed because `4`
char `+` in `c++` is not removed because `2`
char `+` in `c+` was removed because `2`
word: `'Dirty's'.` was replaced to `Dirty's.` because `3` and `4`
char `'` in `beautiful'...` was removed because `3`
char `.` is not removed because of `4`

To jest mój kod javascript:

var str = "abc's test_s c++ c+ 'Dirty's'. and beautiful";
console.log(str);
str = str.replace(/[_]/g, " ");
str = str.replace(/[^a-zA-Z0-9 &-.!]/g, "");
console.log(str);

To jest mój JSFiddle: http://jsfiddle.net/alonshmiel/lkjyd/4/

Nie podoba mi się mój kod, ponieważ jestem pewien, że można to zrobić, uruchamiając raz po sznurku.

Każda pomoc doceniona!

0
Alon Shmiel 7 luty 2015, 17:08

3 odpowiedzi

Ponieważ zamiennik potrzebny może być inny (nic lub przestrzeń), nie można użyć stałego ciągu (ze względu na ograniczenie jednopasowe). Jedynym sposobem jest użycie dynamicznej wymiany.

bezpośrednie podejście:

Spróbujmy znaleźć postacie do usunięcia i zachowania w niektórych przypadkach innych:

var str = "abc's, test_s! & c++ c+ 'Dirty's'. and beautiful'...";

var re = /[^\w\s&.!'+-]+|\B'+|'+\B|(\+{2,})|\+|'*(_)'*/g; 

var result = str.replace(re, function (_, g1, g2) {
    if (g1) return g1;
    return (g2) ? ' ' : ''; });

console.log(result);

Po znalezieniu podkreślenia, grupa przechwytywania 2 jest zdefiniowana (g2 w funkcji wywołania zwrotnego) i zwracana jest przestrzeń.

Uwaga: W powyższym przykładzie termin "słowo" jest wykonany w znaczeniu regexa (klasa znaków \w tak [a-zA-Z0-9_] z wyjątkiem podkreślenia), ale jeśli chcesz być bardziej rygorystyczny, na przykład Wyklucz pojedyncze cytaty w pobliżu cyfr, musisz zmienić wzorcę trochę:

var re = /[^\w\s&.!'+-]+|(_)'*|([^a-z])'+|'+(?![a-z])|(\+{2,})|\+|^'+/gi;

var result = str.replace(re, function (_, g1, g2, g3) {
    if (g2) return g2;
    if (g3) return g3;
    return (g1) ? ' ' : ''; });

Uwaga o dwóch wzorach:

Te dwa wzory składają się na alteracji 6 lub 7 subpatternów, które mogą pasować do większości czasu około 1 lub 2 znaków. Należy Jest to ważny koszt i przez większość czasu charakter nie musi być zastąpiony.

Istnieje sposób na zmniejszenie tego kosztu, które możesz zastosować tutaj: pierwsza dyskryminacja postaci

Chodzi o to, aby uniknąć jak najwięcej do przetestowania każdej subpatoryn. Można to zrobić tutaj, ponieważ wszystkie subpatterns nie zaczynają się od litery, dzięki czemu można szybko pominąć wszystkie znaki, które są listem bez konieczności przetestowania każdej subpatternów, jeśli dodasz lookhead na początku. Przykład dla wzoru 2:

var re = /(?=[^a-z])(?:[^\w\s&.!'+-]+|(_)'*|([^a-z])'+|'+(?![a-z])|(\+{2,})|\+|^'+)/gi;

W pierwszym wzorze można pominąć więcej znaków:

var re = /(?=[^a-z0-9\s&.!-])(?:[^\w\s&.!'+-]+|\B'+|'+\B|(\+{2,})|\+|'*(_)'*)/gi;

Pomimo tych ulepszeń te dwa wzory potrzebują wielu kroków dla małego łańcucha (~ 400) (ale uważać, że jest to przykładowy ciąg ze wszystkimi możliwymi przypadkami) .

Bardziej pośrednie podejście:

Teraz wypróbujmy inny sposób, który polega na znalezieniu postaci do wymiany, ale tym razem ze wszystkimi znakami przed nim.

var re = /((?:[a-z]+(?:'[a-z]+)*|\+{2,}|[\s&.!-]+)*)(?:(_)|.)?/gi

var result = str.replace(re, function (_, g1, g2) {
    return g1 + ((g2) ? ' ' : '' );
});

(zauważ, że nie ma potrzeby, aby zapobiec katastrofalnemu wstecz, ponieważ następuje (?:a+|b+|c+)* następuje zawsze prawdziwy subpattern (?:d|e)?. Obok cały wzór nigdy nie zawiedzie bez względu na ciąg lub pozycji w pozycji to.)

Wszystkie znaki przed postacią zastąpienie (dozwoloną zawartość) są przechwytywane i zwracane przez funkcję zwrotną.

W ten sposób potrzebuje więcej niż 2x mniej kroków, aby wykonać tę samą pracę.

2
Casimir et Hippolyte 16 luty 2015, 13:18

Potrzebujesz operatora łańcuchowego i alternatywnego

function customReplace(str){
   return str.replace(/_/g, " ").replace(/^'|'$|[^a-zA-Z0-9 &-.!]|\+(?=[^+])/g,"");
}

Regex /^'|'$|[^a-zA-Z0-9 &-.!]|\+(?=[^+])/g łączy wszystko, co jest potrzebne do usunięcia. I zastępujemy wszystkie _ przez przestrzeń, którą w końcu wrócimy.

\+(?=[^+]) Szuka +, który następuje cokolwiek z wyjątkiem +

Również zamówienie zastępczego jest ważne.

1
Amit Joki 7 luty 2015, 14:28

Spróbuj tego: przez regex /(?!\b)'|'(?=\B)|^'|'$|[^\w\d\s&-.!]|\+(?=[^+])/gm

function sanitize(str) {
  var re = /(?!\b)'|'(?=\B)|^'|'$|[^\w\d\s&-.!]|\+(?=[^+])/gm;
  var subst = '';
  var tmp = str.replace(re, subst);  // remove all condition without (_) 
  var result = tmp.replace("_", " ");  // next replace (_) by ( ) space.
  return result;
}

document.querySelector('#sanitize').addEventListener('click', function() {

  document.querySelector('#output').innerHTML =
    sanitize(document.querySelector('#inputString').value);
});
#inputString {
  width: 290px
}
#sanitize {
  background: #009afd;
  border: 1px solid #1777b7;
  border: none;
  color: #fff;
  cursor: pointer;
  height: 1.55em;
}
#output {
  background: #eee;
  margin-top: 5px;
  width: 295px;
}
<input id="inputString" type="text" value="abc's test_s! & c++ c+ 'Dirty's'. and beau)'(tiful'..." />
<input id="sanitize" type="button" value="Sanitize it!" />
<div id="output"></div>
1
Ahosan Karim Asik 16 luty 2015, 06:53