regex - regulares - Expresión regular para eliminar un parámetro de la cadena de consulta
regex html tag (8)
Estoy buscando una expresión regular para eliminar un solo parámetro de una cadena de consulta y, si es posible, quiero hacerlo en una sola expresión regular.
Digamos que quiero eliminar el parámetro foo
. Ahora mismo uso esto:
/&?foo/=[^&]+/
Eso funciona siempre que foo
no sea el primer parámetro en la cadena de consulta. Si es así, entonces mi nueva cadena de consulta comienza con un signo. (Por ejemplo, " foo=123&bar=456
" da un resultado de " &bar=456
".) En este momento, solo estoy comprobando después de la expresión regular si la cadena de consulta comienza con un símbolo comercial, y cortándola si es así.
Ejemplos de casos de borde:
Input | Expected Output
-------------------------+--------------------
foo=123 | (empty string)
foo=123&bar=456 | bar=456
bar=456&foo=123 | bar=456
abc=789&foo=123&bar=456 | abc=789&bar=456
Editar
OK, como se señaló en los comentarios, hay muchos más casos de los que originalmente consideré. Conseguí la siguiente expresión regular para trabajar con todos ellos:
/&foo(/=[^&]*)?(?=&|$)|^foo(/=[^&]*)?(&|$)/
Esto se modificó a partir de la respuesta de Mark Byers , que es la razón por la que lo acepto, pero la opinión de Roger Pate también ayudó mucho.
Aquí está el conjunto completo de casos de prueba que estoy usando, y un fragmento de Javascript que los prueba:
$(function() {
var regex = /&foo(/=[^&]*)?(?=&|$)|^foo(/=[^&]*)?(&|$)/;
var escapeHtml = function (str) {
var map = {
''&'': ''&'',
''<'': ''<'',
''>'': ''>'',
''"'': ''"'',
"''": '''''
};
return str.replace(/[&<>"'']/g, function(m) { return map[m]; });
};
//test cases
var tests = [
''foo'' , ''foo&bar=456'' , ''bar=456&foo'' , ''abc=789&foo&bar=456''
,''foo='' , ''foo=&bar=456'' , ''bar=456&foo='' , ''abc=789&foo=&bar=456''
,''foo=123'' , ''foo=123&bar=456'' , ''bar=456&foo=123'' , ''abc=789&foo=123&bar=456''
,''xfoo'' , ''xfoo&bar=456'' , ''bar=456&xfoo'' , ''abc=789&xfoo&bar=456''
,''xfoo='' , ''xfoo=&bar=456'' , ''bar=456&xfoo='' , ''abc=789&xfoo=&bar=456''
,''xfoo=123'', ''xfoo=123&bar=456'', ''bar=456&xfoo=123'', ''abc=789&xfoo=123&bar=456''
,''foox'' , ''foox&bar=456'' , ''bar=456&foox'' , ''abc=789&foox&bar=456''
,''foox='' , ''foox=&bar=456'' , ''bar=456&foox='' , ''abc=789&foox=&bar=456''
,''foox=123'', ''foox=123&bar=456'', ''bar=456&foox=123'', ''abc=789&foox=123&bar=456''
];
//expected results
var expected = [
'''' , ''bar=456'' , ''bar=456'' , ''abc=789&bar=456''
,'''' , ''bar=456'' , ''bar=456'' , ''abc=789&bar=456''
,'''' , ''bar=456'' , ''bar=456'' , ''abc=789&bar=456''
,''xfoo'' , ''xfoo&bar=456'' , ''bar=456&xfoo'' , ''abc=789&xfoo&bar=456''
,''xfoo='' , ''xfoo=&bar=456'' , ''bar=456&xfoo='' , ''abc=789&xfoo=&bar=456''
,''xfoo=123'', ''xfoo=123&bar=456'', ''bar=456&xfoo=123'', ''abc=789&xfoo=123&bar=456''
,''foox'' , ''foox&bar=456'' , ''bar=456&foox'' , ''abc=789&foox&bar=456''
,''foox='' , ''foox=&bar=456'' , ''bar=456&foox='' , ''abc=789&foox=&bar=456''
,''foox=123'', ''foox=123&bar=456'', ''bar=456&foox=123'', ''abc=789&foox=123&bar=456''
];
for(var i = 0; i < tests.length; i++) {
var output = tests[i].replace(regex, '''');
var success = (output == expected[i]);
$(''#output'').append(
''<tr class="'' + (success ? ''passed'' : ''failed'') + ''">''
+ ''<td>'' + (success ? ''PASS'' : ''FAIL'') + ''</td>''
+ ''<td>'' + escapeHtml(tests[i]) + ''</td>''
+ ''<td>'' + escapeHtml(output) + ''</td>''
+ ''<td>'' + escapeHtml(expected[i]) + ''</td>''
+ ''</tr>''
);
}
});
#output {
border-collapse: collapse;
}
#output tr.passed { background-color: #af8; }
#output tr.failed { background-color: #fc8; }
#output td, #output th {
border: 1px solid black;
padding: 2px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<table id="output">
<tr>
<th>Succ?</th>
<th>Input</th>
<th>Output</th>
<th>Expected</th>
</tr>
</table>
Es un poco tonto, pero empecé a tratar de resolver esto con una expresión regular y quería que finalmente funcionara :)
$str[] = ''foo=123'';
$str[] = ''foo=123&bar=456'';
$str[] = ''bar=456&foo=123'';
$str[] = ''abc=789&foo=123&bar=456'';
foreach ($str as $string) {
echo preg_replace(''#(?:^|/b)(&?)foo=[^&]+(&?)#e'', "''$1''==''&'' && ''$2''==''&'' ? ''&'' : ''''", $string), "/n";
}
la parte de reemplazo está desordenada porque aparentemente se confunde si los caracteres capturados son ''&''
s
Además, no coincide con afoo
y similares.
Gracias. Sí, usa barras invertidas para escapar, y tienes razón, no necesito las / ''s.
Esto parece funcionar, aunque no lo hace en una línea como se solicita en la pregunta original.
public static string RemoveQueryStringParameter(string url, string keyToRemove)
{
//if first parameter, leave ?, take away trailing &
string pattern = @"/?" + keyToRemove + "[^&]*&?";
url = Regex.Replace(url, pattern, "?");
//if subsequent parameter, take away leading &
pattern = "&" + keyToRemove + "[^&]*";
url = Regex.Replace(url, pattern, "");
return url;
}
Me basé en su implementación para obtener un implemento de Java que parece funcionar:
public static String removeParameterFromQueryString(String queryString,String paramToRemove) {
Preconditions.checkArgument(queryString != null,"Empty querystring");
Preconditions.checkArgument(paramToRemove != null,"Empty param");
String oneParam = "^"+paramToRemove+"(=[^&]*)$";
String begin = "^"+paramToRemove+"(=[^&]*)(&?)";
String end = "&"+paramToRemove+"(=[^&]*)$";
String middle = "(?<=[&])"+paramToRemove+"(=[^&]*)&";
String removedMiddleParams = queryString.replaceAll(middle,"");
String removedBeginParams = removedMiddleParams.replaceAll(begin,"");
String removedEndParams = removedBeginParams.replaceAll(end,"");
return removedEndParams.replaceAll(oneParam,"");
}
En algunos casos tuve problemas con su implementación porque a veces no eliminaba un &
, y lo hacía con varios pasos que parecían más fáciles de entender.
Tuve un problema con tu versión, particularmente cuando un parámetro estaba en la cadena de consulta varias veces (como param1 = toto & param2 = xxx & param1 = YYY & param3 = ZZZ & param1 ....)
Para cualquier persona interesada en reemplazar los parámetros de solicitud GET:
La siguiente expresión regular funciona también para consultas de métodos GET más generales (comenzando con?) Donde la respuesta marcada falla si el parámetro que se eliminará es el primero (¿después?)
Esta expresión regular (sabor de JS) se puede usar para eliminar el parámetro independientemente de la posición (primero, último o intermedio) dejando la consulta en un estado bien formado.
Así que solo use un reemplazo de expresiones regulares con una cadena vacía.
/&s=[^&]*()|/?s=[^&]*$|s=[^&]*&/
Básicamente coincide con uno de los tres casos mencionados anteriormente (de ahí los 2 tubos)
Puede utilizar la siguiente expresión regular:
[/?|&](?<name>.*?)=[^&]*&?
Si desea hacer una coincidencia exacta, puede reemplazar (?<name>.*?)
Con un parámetro url. p.ej:
[/?|&]foo=[^&]*&?
para que coincida con cualquier variable como foo=xxxx
en cualquier URL.
Si desea hacer esto en una sola expresión regular, puede hacer esto:
/&foo(=[^&]*)?|^foo(=[^&]*)?&?/
Esto se debe a que es necesario que coincida con un ampersand antes de foo = ..., o uno después, o ninguno, pero no ambos.
Para ser honesto, creo que es mejor la forma en que lo hizo: eliminar los signos y el final en un paso separado.
Tener una cadena de consulta que comienza con &
es inofensiva, ¿por qué no dejarla así? En cualquier caso, te sugiero que busques el símbolo y el final y utilices /b
para que coincida con el principio de foo w / o tomando un carácter anterior:
//bfoo/=[^&]+&?/
/(?<=&|/?)foo(=[^&]*)?(&|$)/
Utiliza lookbehind y el último grupo para "anclar" la coincidencia, y permite un valor faltante. Cambiar el /?
a ^
si ya ha eliminado el signo de interrogación de la cadena de consulta.
Regex todavía no es un sustituto para un analizador real de la cadena de consulta, sin embargo.
Actualización: script de prueba: (ejecútelo en codepad.org )
import re
regex = r"(^|(?<=&))foo(=[^&]*)?(&|$)"
cases = {
"foo=123": "",
"foo=123&bar=456": "bar=456",
"bar=456&foo=123": "bar=456",
"abc=789&foo=123&bar=456": "abc=789&bar=456",
"oopsfoo=123": "oopsfoo=123",
"oopsfoo=123&bar=456": "oopsfoo=123&bar=456",
"bar=456&oopsfoo=123": "bar=456&oopsfoo=123",
"abc=789&oopsfoo=123&bar=456": "abc=789&oopsfoo=123&bar=456",
"foo": "",
"foo&bar=456": "bar=456",
"bar=456&foo": "bar=456",
"abc=789&foo&bar=456": "abc=789&bar=456",
"foo=": "",
"foo=&bar=456": "bar=456",
"bar=456&foo=": "bar=456",
"abc=789&foo=&bar=456": "abc=789&bar=456",
}
failures = 0
for input, expected in cases.items():
got = re.sub(regex, "", input)
if got != expected:
print "failed: input=%r expected=%r got=%r" % (input, expected, got)
failures += 1
if not failures:
print "Success"
Muestra dónde falló mi enfoque, Mark tiene el derecho de hacerlo, lo que debería mostrar por qué no debería hacer esto con expresiones regulares ...: P
El problema es asociar el parámetro de consulta con exactamente un signo y, si debe usar expresiones regulares (si no lo ha detectado: P, usaría un analizador por separado, que podría usar expresiones regulares en su interior, pero en realidad entienda el formato): una solución sería asegurarse de que exista exactamente un símbolo por símbolo: ¿reemplazar el encabezado ?
con un &
.
Esto da a /&foo(=[^&]*)?(?=&|$)/
, Que es muy sencillo y lo mejor que vas a obtener. Elimine el encabezado &
en el resultado final (o cámbielo nuevamente a ?
Etc.). La modificación del caso de prueba para hacer esto usa los mismos casos anteriores y cambia el bucle a:
failures = 0
for input, expected in cases.items():
input = "&" + input
got = re.sub(regex, "", input)
if got[:1] == "&":
got = got[1:]
if got != expected:
print "failed: input=%r expected=%r got=%r" % (input, expected, got)
failures += 1
if not failures:
print "Success"