examples - split string java delimiter
Regex para dividir una cadena usando espacio cuando no está rodeado por comillas simples o dobles (13)
Soy nuevo en expresiones regulares y agradecería su ayuda. Estoy tratando de armar una expresión que dividirá la cadena de ejemplo utilizando todos los espacios que no están rodeados por comillas simples o dobles. Mi último intento se ve así: (?!")
Y no funciona del todo. Se está dividiendo en el espacio antes de la cita.
Ejemplo de entrada:
This is a string that "will be" highlighted when your ''regular expression'' matches something.
Salida deseada:
This
is
a
string
that
will be
highlighted
when
your
regular expression
matches
something.
Tenga en cuenta que "will be"
y ''regular expression''
conservan el espacio entre las palabras.
El enfoque de Jan es genial, pero aquí hay otro para el registro.
Si realmente desea dividir como se menciona en el título, manteniendo las comillas en "will be"
y ''regular expression''
, entonces podría usar este método que está directamente fuera de Coincidencia (o reemplazar) un patrón excepto en las situaciones s1, s2 , s3 etc.
La expresión regular:
''[^'']*''|/"[^/"]*/"|( )
Las dos alternancias de la izquierda coinciden con las ''quoted strings''
y "double-quoted strings"
. Ignoraremos estos partidos. El lado derecho coincide y captura espacios para el Grupo 1, y sabemos que son los espacios correctos porque no se correspondían con las expresiones de la izquierda. Reemplazamos esos con SplitHere
luego los dividimos en SplitHere
. Una vez más, esto es para un verdadero caso dividido en el que desea "will be"
, no will be
.
Aquí hay una implementación completa (vea los resultados en la demostración en línea ).
import java.util.*;
import java.io.*;
import java.util.regex.*;
import java.util.List;
class Program {
public static void main (String[] args) throws java.lang.Exception {
String subject = "This is a string that /"will be/" highlighted when your ''regular expression'' matches something.";
Pattern regex = Pattern.compile("/'[^'']*''|/"[^/"]*/"|( )");
Matcher m = regex.matcher(subject);
StringBuffer b= new StringBuffer();
while (m.find()) {
if(m.group(1) != null) m.appendReplacement(b, "SplitHere");
else m.appendReplacement(b, m.group(0));
}
m.appendTail(b);
String replaced = b.toString();
String[] splits = replaced.split("SplitHere");
for (String split : splits) System.out.println(split);
} // end main
} // end Program
Estoy razonablemente seguro de que esto no es posible solo con expresiones regulares. Comprobar si algo está contenido dentro de otra etiqueta es una operación de análisis sintáctico. Esto parece ser el mismo problema que tratar de analizar XML con una expresión regular: no se puede hacer correctamente. Puede obtener el resultado deseado aplicando repetidamente una expresión regular no codiciosa y no global que coincida con las cadenas entrecomilladas, luego, una vez que no puede encontrar nada más, divídala en los espacios ... que tiene una cantidad de problemas, incluido el seguimiento del orden original de todas las subcadenas. Su mejor opción es simplemente escribir una función realmente simple que itere sobre la cadena y extraiga los tokens que desee.
Hay varias preguntas en que cubren esta misma pregunta en varios contextos utilizando expresiones regulares. Por ejemplo:
- cadenas de análisis: extracción de palabras y frases
- La mejor manera de analizar el texto separado del espacio
ACTUALIZACIÓN : Muestra de expresión regular para manejar cadenas simples y dobles entre comillas. Ref .: ¿Cómo puedo dividir en una cadena, excepto cuando está dentro de las comillas?
m/(''.*?''|".*?"|/S+)/g
Probado esto con un fragmento de Perl rápido y la salida fue como se reproduce a continuación. También funciona para cadenas vacías o cadenas solo de espacio en blanco si están entre comillas (no estoy seguro de si eso es deseado o no).
This
is
a
string
that
"will be"
highlighted
when
your
''regular expression''
matches
something.
Tenga en cuenta que esto incluye los caracteres de comillas en los valores coincidentes, aunque puede eliminarlos con un reemplazo de cadena o modificar la expresión regular para que no los incluya. Lo dejaré como un ejercicio para el lector u otro póster por el momento, ya que las 2am ya es demasiado tarde para estar jugando con expresiones regulares;)
La expresión regular de Jan Goyvaerts es la mejor solución que encontré hasta ahora, pero crea también coincidencias vacías (nulas), que él excluye en su programa. Estas coincidencias vacías también aparecen de probadores de expresiones regulares (por ejemplo, rubular.com). Si activas las búsquedas (primero busca las partes citadas y el espacio separado de las palabras) entonces puedes hacerlo de una vez con:
("[^"]*"|''[^'']*''|[/S]+)+
Me gustó el enfoque de Marcus, sin embargo, lo modifiqué para permitir el texto cerca de las comillas y admitir los caracteres de comillas "y". Por ejemplo, necesitaba a = "algún valor" para no dividirlo en [a =, " algún valor "].
(?<!//G//S{0,99999}[/"''].{0,99999})//s|(?<=//G//S{0,99999}/".{0,99999}/"//S{0,99999})//s|(?<=//G//S{0,99999}''.{0,99999}''//S{0,99999})//s"
No entiendo por qué todos los demás están proponiendo expresiones regulares tan complejas o código tan largo. Básicamente, desea obtener dos tipos de cosas de su cadena: secuencias de caracteres que no son espacios o comillas, y secuencias de caracteres que comienzan y terminan con una cita, sin comillas intermedias, para dos tipos de comillas. Puede hacer coincidir fácilmente esas cosas con esta expresión regular:
[^/s"'']+|"([^"]*)"|''([^'']*)''
Agregué los grupos de captura porque no quieres las comillas en la lista.
Este código de Java crea la lista, agrega el grupo de captura si coincide para excluir las comillas y agrega la coincidencia global de expresiones regulares si el grupo de captura no concuerda (se hizo coincidir una palabra sin comillas).
List<String> matchList = new ArrayList<String>();
Pattern regex = Pattern.compile("[^//s/"'']+|/"([^/"]*)/"|''([^'']*)''");
Matcher regexMatcher = regex.matcher(subjectString);
while (regexMatcher.find()) {
if (regexMatcher.group(1) != null) {
// Add double-quoted string without the quotes
matchList.add(regexMatcher.group(1));
} else if (regexMatcher.group(2) != null) {
// Add single-quoted string without the quotes
matchList.add(regexMatcher.group(2));
} else {
// Add unquoted word
matchList.add(regexMatcher.group());
}
}
Si no te importa tener las comillas en la lista devuelta, puedes usar un código mucho más simple:
List<String> matchList = new ArrayList<String>();
Pattern regex = Pattern.compile("[^//s/"'']+|/"[^/"]*/"|''[^'']*''");
Matcher regexMatcher = regex.matcher(subjectString);
while (regexMatcher.find()) {
matchList.add(regexMatcher.group());
}
Probablemente sea más fácil buscar la cadena, agarrando cada parte, dividirla.
Por lo que respecta a la razón, puede dividirlo en los espacios antes y después de "will be"
. Pero no puedo pensar en ninguna forma de especificar ignorando el espacio entre una división.
(no es Java real)
string = "This is a string that /"will be/" highlighted when your ''regular expression'' matches something.";
regex = "/"(///"|(?!///").)+/"|[^ ]+"; // search for a quoted or non-spaced group
final = new Array();
while (string.length > 0) {
string = string.trim();
if (Regex(regex).test(string)) {
final.push(Regex(regex).match(string)[0]);
string = string.replace(regex, ""); // progress to next "word"
}
}
Además, la captura de comillas simples podría generar problemas:
"Foo''s Bar ''n Grill"
//=>
"Foo"
"s Bar "
"n"
"Grill"
Si desea permitir cotizaciones escapadas dentro de la cadena, puede usar algo como esto:
(?:([''"])(.*?)(?<!//)(?>////)*/1|([^/s]+))
Las cadenas citadas serán del grupo 2, las palabras simples sin comillas serán el grupo 3.
Puedes probarlo en varias cadenas aquí: http://www.fileformat.info/tool/regex.htm o http://gskinner.com/RegExr/
Si usa c #, puede usar
string input= "This is a string that /"will be/" highlighted when your ''regular expression'' matches <something random>";
List<string> list1 =
Regex.Matches(input, @"(?<match>/w+)|/""(?<match>[/w/s]*)""|''(?<match>[/w/s]*)''|<(?<match>[/w/s]*)>").Cast<Match>().Select(m => m.Groups["match"].Value).ToList();
foreach(var v in list1)
Console.WriteLine(v);
He agregado específicamente " | <(? [/ W / s] *)> " para resaltar que puede especificar cualquier char para agrupar frases. (En este caso, estoy usando <> para agrupar.
La salida es:
This
is
a
string
that
will be
highlighted
when
your
regular expression
matches
something random
También puedes probar esto:
String str = "This is a string that /"will be/" highlighted when your ''regular expression'' matches something";
String ss[] = str.split("/"|/'");
for (int i = 0; i < ss.length; i++) {
if ((i % 2) == 0) {//even
String[] part1 = ss[i].split(" ");
for (String pp1 : part1) {
System.out.println("" + pp1);
}
} else {//odd
System.out.println("" + ss[i]);
}
}
Una pareja con la ayuda de ajustes útiles en la respuesta aceptada de Jan:
([''"])((?:///1|.)+?)/1|([^/s"'']+)
- Permite las comillas escapadas dentro de las cadenas citadas
- Evita repetir el patrón para la comilla simple y doble; esto también simplifica la adición de más símbolos de cotización si es necesario (a expensas de otro grupo de captura)
String.split()
no es útil aquí porque no hay forma de distinguir entre espacios entre comillas (no dividir) y aquellos fuera (división). Matcher.lookingAt()
es probablemente lo que necesita:
String str = "This is a string that /"will be/" highlighted when your ''regular expression'' matches something.";
str = str + " "; // add trailing space
int len = str.length();
Matcher m = Pattern.compile("((/"[^/"]+?/")|(''[^'']+?'')|([^//s]+?))//s++").matcher(str);
for (int i = 0; i < len; i++)
{
m.region(i, len);
if (m.lookingAt())
{
String s = m.group(1);
if ((s.startsWith("/"") && s.endsWith("/"")) ||
(s.startsWith("''") && s.endsWith("''")))
{
s = s.substring(1, s.length() - 1);
}
System.out.println(i + ": /"" + s + "/"");
i += (m.group(0).length() - 1);
}
}
que produce el siguiente resultado:
0: "This"
5: "is"
8: "a"
10: "string"
17: "that"
22: "will be"
32: "highlighted"
44: "when"
49: "your"
54: "regular expression"
75: "matches"
83: "something."
(?<!/G".{0,99999})/s|(?<=/G".{0,99999}")/s
Esto coincidirá con los espacios que no están rodeados por comillas dobles. Tengo que usar min, max {0,99999} porque Java no admite * y + en lookbehind.