java - una - reaccion acido nitrico y plata
Reconocer una cadena de fecha arbitraria (14)
¿Tal vez deberías usar expresiones regulares?
Esperemos que este funcione para el formato mm-dd-aaaa:
^(0[1-9]|1[012])[- /.](0[1-9]|[12][0-9]|3[01])[- /.](19|20)/d/d$
Aquí (0[1-9]|1[012])
coincide con el mes 00..12, (0[1-9]|[12][0-9]|3[01])
coincide con una fecha 00 .. 31 y (19|20)/d/d
coincide con un año.
Los campos pueden ser eliminados por guiones, barras o un punto.
Saludos, Serge
Necesito poder reconocer las cadenas de fecha. No importa si no puedo distinguir entre el mes y la fecha (p. Ej. 12/12/10), solo tengo que clasificar la cadena como una fecha, en lugar de convertirla en un objeto Date. Entonces, esto es realmente una clasificación en lugar de un problema de análisis.
Tendré pedazos de texto tales como:
"bla bla bla bla 12 de enero de 2009 bla bla bla 01/04/10 bla bla bla"
y necesito poder reconocer el límite de inicio y final para cada cadena de fecha dentro.
Me preguntaba si alguien sabía de cualquier biblioteca de Java que pueda hacer esto. Mi google-fu no ha encontrado nada hasta ahora.
ACTUALIZACIÓN: Necesito poder reconocer el conjunto más amplio posible de formas de representar una fecha. Por supuesto, la solución ingenua podría ser escribir una declaración if para cada formato concebible, pero un enfoque de reconocimiento de patrones , con un modelo entrenado, es idealmente lo que busco.
No sé de ninguna biblioteca que haga esto tampoco. Sugeriría una combinación de funciones recursivas anidadas y expresiones regulares (mucho) para hacer coincidir cadenas y tratar de llegar a una mejor estimación para ver si puede ser una fecha. Las fechas se pueden escribir de muchas maneras diferentes, algunas personas pueden escribirlas como "Domingo, 3 de octubre de 2010" o "Domingo, 3 de octubre de 2010" o "10/03/2010" o "10/3/2010" y un montón de maneras diferentes (incluso más si está considerando fechas en otros idiomas / culturas).
No sé de ninguna biblioteca que pueda hacer esto, pero escribir la suya no sería increíblemente difícil. Asumiendo que todas las fechas estén formateadas con barras como 12/12/12
entonces podría verificar que tiene tres ''/'. Puede obtener aún más técnico y hacer que verifique los valores entre las barras. Por ejemplo, si tienes:
30/12/10
Entonces sabes que 30 son los días y 12 es el mes. Sin embargo, si obtiene el 30/30/10, sabrá que aunque tiene el formato correcto, no puede ser una fecha porque no hay ''30'' meses.
Por lo general, las fechas son caracteres separados por una barra invertida / anterior o un guión. ¿Consideraste una expresión regular?
Supongo que no está buscando clasificar las fechas del tipo el domingo 3 de octubre de 2010, etc.
Siempre puedes verificar si hay dos caracteres ''/'' en una cadena.
public static boolean isDate(){
String date = "12/25/2010";
int counter = 0;
for(int i=0; i<date.length(); i++){
if ("//-.".indexOf(date.charAt(i)) != -1) //Any symbol can be used.
counter++;
}
if(counter == 2) //If there are two symbols in the string,
return true; //Return true.
else
return false;
}
Puede hacer algo similar para verificar si todo lo demás es un número entero.
Es virtualmente imposible reconocer todos los posibles formatos de fecha como fechas usando algoritmos "estándar". Eso es solo porque hay muchos de ellos.
Nosotros, los humanos, somos capaces de hacer eso solo porque aprendimos que algo como 2010-03-31 se asemeja a la fecha. En otras palabras, sugeriría usar algoritmos de Machine Learning y enseñarle a su programa a reconocer secuencias de fechas válidas. Con Google Prediction API eso debería ser factible.
O puede usar expresiones regulares como se sugiere arriba, para detectar algunos formatos de fecha, pero no todos.
Estoy seguro de que los investigadores en la extracción de información han analizado este problema, pero no pude encontrar un documento.
Una cosa que puedes intentar es hacerlo como un proceso de dos pasos. (1) después de recopilar tantos datos como sea posible, extraiga las características, algunas características que le vienen a la mente: cantidad de números que aparecen en la cadena, cantidad de números del 1 al 31 que aparecen en la cadena, cantidad de números del 1 12 que aparecen en la cadena, la cantidad de meses que aparecen en la cadena, etc. (2) aprenda de las características usando algún tipo de método de clasificación binario (SVM, por ejemplo) y finalmente (3) cuando aparezca una nueva cadena, extraiga las características y consulte el SVM para una predicción.
Puede recorrer todos los formatos de fecha disponibles en Java:
for (Locale locale : DateFormat.getAvailableLocales()) {
for (int style = DateFormat.FULL; style <= DateFormat.SHORT; style ++) {
DateFormat df = DateFormat.getDateInstance(style, locale);
try {
df.parse(dateString);
// either return "true", or return the Date obtained Date object
} catch (ParseException ex) {
continue; // unperasable, try the next one
}
}
}
Sin embargo, esto no tendrá en cuenta ningún formato de fecha personalizado.
Lo hice con una enorme expresión regular (creación propia):
public static final String DATE_REGEX = "/b([0-9]{1,2} ?([//-/////] ?[0-9]{1,2} ?| (Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec) ?)([//-/////]? ?(''?[0-9]{2}|[0-9]{4}))?)/b";
public static final Pattern DATE_PATTERN = Pattern.compile(DATE_REGEX, Pattern.CASE_INSENSITIVE); // Case insensitive is to match also "mar" and not only "Mar" for March
public static boolean containsDate(String str)
{
Matcher matcher = pattern.matcher(str);
return matcher.matches();
}
Esto coincide con las siguientes fechas:
06 Sep 2010
12-5-2005
07 Mar 95
30 DEC ''99
11/9/2001
Y no esto:
444/11/11
bla11/11/11
11/11/11blah
También coincide con fechas entre símbolos como []
, ()
,
:
Yesterday (6 nov 2010)
Coincide con las fechas sin año:
Yesterday, 6 nov, was a rainy day...
Pero coincide :
86-44/1234
00-00-0000
11/11/11
Y esto ya no parece una cita. Pero esto es algo que puede resolver comprobando si los números son valores posibles para un mes, día, año.
Lo que haría es buscar las características de fecha, en lugar de las fechas en sí. Por ejemplo, puede buscar barras inclinadas, (para obtener fechas del formulario 1/1/1001), guiones (1 - 1 - 1001), nombres de los meses y abreviaturas (1 de enero de 1001 o 1 de enero de 1001). Cuando obtenga un golpe para estos, recopile las palabras cercanas (2 de cada lado deberían estar bien) y almacénelas en una serie de cadenas. Una vez que haya escaneado todas las entradas, consulte esta matriz de cadenas con una función que profundizará un poco más y extraiga las cadenas de fechas reales, utilizando los métodos que se encuentran aquí. Lo importante es simplemente bajar las fechas generales a un nivel manejable.
Reglas que pueden ayudarte en tu búsqueda:
- Haga o encuentre una especie de base de datos con palabras conocidas que coincidan con meses. Nombres abreviados y completos, como
Jan
oJanuary
. Durante la búsqueda, debe ser insensible a las mayúsculas y minúsculas, porque fEBruaRy también es un mes, aunque la persona que lo escribió debe haber estado borracha. Si planeas buscar meses que no sean en inglés, también se necesita una base de datos, porque ninguna heurística descubrirá que "WrzesieĊ" es polaco para septiembre. - Solo para inglés, consulte los números ordinales y también haga una base de datos para los números del 1 al 31. Estos serán útiles por días y meses. Si desea utilizar este enfoque para otros idiomas, tendrá que hacer su propia investigación.
- Una vez más, solo en inglés, busque "Anno Domini" y "Before Christ", es decir, AD y BC, respectivamente. También pueden estar en forma AD y BC
- Con respecto a los números mismos que representarán días, meses y años, debe saber dónde está su límite. ¿Es 0-9999 o más? Es decir, ¿desea buscar fechas que representen años posteriores al año 9999? Si no, entonces las cadenas que tienen 1-4 dígitos consecutivos son buenas suposiciones para un día, mes o año válido.
- Los días y los meses tienen uno o dos dígitos. Los ceros iniciales son aceptables, por lo que las cadenas con un formato de
0*
, donde * pueden ser de 1 a 9 son aceptables. - Los separadores pueden ser complicados, pero si no permite un formato incoherente como 10/20 / 1999, entonces se ahorrará mucho dolor. Esto se debe a que 10 * 20 * 1999 puede ser una fecha válida, siendo * por lo general un elemento del conjunto
{-,_, ,:,/,/,.,'',''}
, Pero es posible que * sea una combinación de 2 o 3 elementos del conjunto mencionado. Una vez más, debes elegir separadores aceptables. 10-20? 1999 puede ser una fecha válida para alguien con un extraño sentido de la elegancia. 20/10/1999 también puede ser una fecha válida, pero 10_ / 20_ / 1999 sería muy extraño. - Hay casos sin separador Por ejemplo: 10 de enero de 1988. Estos casos usan palabras de 1.
- Hay casos especiales, como el 28 o el 29 de febrero, dependiendo del año bisiesto. Además, meses con 30 o 31 días.
Creo que estos son suficientes para una clasificación "ingenua", un experto lingüista podría ayudarlo más.
Ahora, una idea para tu algoritmo. La velocidad no importa. Puede haber múltiples pases sobre la misma cadena. Optimiza cuando comienza a importar. Cuando dude que ha encontrado una cadena de fecha, guárdela en algún lugar "seguro" en un ListOfPossibleDates
y haga un examen una vez más, con reglas más rígidas usando combinaciones de 1. a 8. Cuando crea que una cadena de fecha es válida, aliméntela a la clase Date
para ver si es realmente válido. El 32 de marzo de 1999 no es válido cuando lo convierte a un formato que la Date
comprenderá.
Un patrón recurrente importante es lookbehind y lookaround. Cuando crees que se encuentra una entidad válida (día, mes, año), tendrás que ver qué hay detrás y qué hay detrás. Un mecanismo basado en pila o recursión puede ayudar aquí.
Pasos:
- Busque en su cadena las palabras de la regla 1. Si encuentra alguna, tenga en cuenta esa ubicación. Tenga en cuenta el mes. Ahora, ve algunos personajes detrás y algunos adelante para ver lo que te espera. Si no hay espacios antes y después de su mes, y hay números, como en la regla 7., verifique su validez. Si uno de ellos representa un día (debe ser 0-31) y otro al año (debe ser 0-9999, posiblemente con AD o BC), tiene un candidato. Si hay los mismos separadores antes y después, busque las reglas de 6. Recuerde siempre que debe estar seguro de que existe una combinación válida. entonces, 32 de enero de 1999 no funcionará.
- Busque en su cadena otras palabras en inglés, de las reglas 2. y 3. Repita de manera similar a como en el paso 1.
- Busque separadores El espacio vacío será el más complicado. Intenta encontrarlos en pares. Entonces, si tiene una "/" en su cadena, busque otra y vea lo que tienen entremedio. Si encuentra una combinación de separadores, haga lo mismo. Además, usa el algoritmo del paso 2.
- Busque los dígitos Los válidos son 0-9999 con ceros a la izquierda permitidos. Si encuentra uno, busque separadores como en el paso 3.
Dado que hay literalmente una gran cantidad de posibilidades, no podrás atraparlas todas. Una vez que haya encontrado un patrón que cree que podría ocurrir nuevamente, guárdelo en algún lugar y puede usarlo como expresión regular para pasar otras cadenas.
Tomemos el ejemplo: "bla bla bla bla 12 Jan 09 bla bla bla 01/04/10 bla bla bla"
. Después de extraer la primera fecha, 12 Jan 09
, utilice el resto de la cadena ( "bla bla bla 01/04/10 bla bla bla"
) y aplique todos los pasos anteriores una vez más. De esta forma, estarás seguro de que no te perdiste nada.
Espero que estas sugerencias sean al menos de alguna ayuda. Si no existe una biblioteca para hacer todos estos pasos sucios (y más), entonces tiene un camino difícil por delante. ¡Buena suerte!
Use JChronic
Es posible que desee utilizar DateParser2 del paquete edu.mit.broad.genome.utils.
Aquí hay un ejemplo simple de ingenio:
import com.joestelmach.natty.*;
List<Date> dates =new Parser().parse("Start date 11/30/2013 , end date Friday, Sept. 7, 2013").get(0).getDates();
System.out.println(dates.get(0));
System.out.println(dates.get(1));
//output:
//Sat Nov 30 11:14:30 BDT 2013
//Sat Sep 07 11:14:30 BDT 2013