Analizar la cadena de una columna y llenar otra columnaHola,
Tengo una tabla que contiene ProductName y quiero generar la columna SALIDA.La columna SALIDA es una concatenación de ProductID con Serial#. ¿Cómo analizo con precisión el número de serie y creo la columna SALIDA?
Ejemplos de número de serie:
- 07-08_13 significa Número de serie 07, 08, 13
- 09-12 significa Número de serie 09, 10, 11, 12
- 01-03_05-08 significa Número de serie 01, 02, 03, 05, 06, 07, 08
- 01_04_05-08 significa Número de serie 01, 04, 05, 06, 07, 08
- 09_11_13_14 significa número de serie 09,11,13,14

| Nombre del producto | PRODUCCIÓN |
| AABBCC_07-08_13 | AABBCC-07 |
| AABBCC_07-08_13 | AABBCC-08 |
| AABBCC_07-08_13 | AABBCC-13 |
| AABBCC_09-12 | AABBCC-09 |
| AABBCC_09-12 | AABBCC-10 |
| AABBCC_09-12 | AABBCC-11 |
| AABBCC_09-12 | AABBCC-12 |
| EEFFGG_02 | EEFFGG-02 |
| HHIIJJ_01-07 | HHIIJJ-01 |
| HHIIJJ_01-07 | HHIIJJ-02 |
| HHIIJJ_01-07 | HHIIJJ-03 |
| HHIIJJ_01-07 | HHIIJJ-04 |
| HHIIJJ_01-07 | HHIIJJ-05 |
| HHIIJJ_01-07 | HHIIJJ-06 |
| HHIIJJ_01-07 | HHIIJJ-07 |
| KKLLLMM_01-03_05-08 | KKLLLMM-01 |
| KKLLLMM_01-03_05-08 | KKLLLMM-02 |
| KKLLLMM_01-03_05-08 | KKLLLMM-03 |
| KKLLLMM_01-03_05-08 | KKLLLMM-05 |
| KKLLLMM_01-03_05-08 | KKLLLMM-06 |
| KKLLLMM_01-03_05-08 | KKLLLMM-07 |
| KKLLLMM_01-03_05-08 | KKLLLMM-08 |
| NNOOPP_01_04_05-08 | NNOOPP-01 |
| NNOOPP_01_04_05-08 | NNOOPP-04 |
| NNOOPP_01_04_05-08 | NNOOPP-05 |
| NNOOPP_01_04_05-08 | NNOOPP-06 |
| NNOOPP_01_04_05-08 | NNOOPP-07 |
| NNOOPP_01_04_05-08 | NNOOPP-08 |
| QQRRSS_09_11_13_14 | QQRRSS_09 |
| QQRRSS_09_11_13_14 | QQRRSS_11 |
| QQRRSS_09_11_13_14 | QQRRSS_13 |
| QQRRSS_09_11_13_14 | QQRRSS_14 |
Modelado estadístico avanzadoLa personalización en masaRe: Analizar cadena de una columna y llenar otra columnaSí, puedes, pero tendrás que resolver la lógica de cuándo agregar nuevas filas, etc.Lo que sugiero es que lo que hagas sea ejecutar el código tal cual y luego usarlo
Tablas=>Unirse
para juntar las 2 tablas de datos.
Re: Analizar cadena de una columna y llenar otra columnaHola Jim,
¿Se puede hacer de manera que no haya dt2? ¿Puedes agregar las columnas ProductID y Output en dt?
¡Gracias!
Re: Analizar cadena de una columna y llenar otra columnaDebido a que los datos se ingresan manualmente, lo más probable es que esto no maneje todos los casos especiales, pero parece funcionar con los valores actuales:
Names Default To Here(1);
//Test table
/*
dt = New Table("Untitled 4993",
Compress File When Saved(1),
New Column("ProductName",
Character,
"Nominal",
Set Values(
{"AABBCC_07-08_13", "AABBCC_07-08_13", "AABBCC_07-08_13", "AABBCC_09-12", "AABBCC_09-12", "AABBCC_09-12", "AABBCC_09-12", "EEFFGG_02",
"HHIIJJ_01-07", "HHIIJJ_01-07", "HHIIJJ_01-07", "HHIIJJ_01-07", "HHIIJJ_01-07", "HHIIJJ_01-07", "HHIIJJ_01-07", "KKLLLMM_01-03_05-08",
"KKLLLMM_01-03_05-08", "KKLLLMM_01-03_05-08", "KKLLLMM_01-03_05-08", "KKLLLMM_01-03_05-08", "KKLLLMM_01-03_05-08", "KKLLLMM_01-03_05-08",
"NNOOPP_01_04_05-08", "NNOOPP_01_04_05-08", "NNOOPP_01_04_05-08", "NNOOPP_01_04_05-08", "NNOOPP_01_04_05-08", "NNOOPP_01_04_05-08",
"QQRRSS_09_11_13_14", "QQRRSS_09_11_13_14", "QQRRSS_09_11_13_14", "QQRRSS_09_11_13_14", "N4TA47_13-14-15-16-17-18", "N4TA59_13-19", "N4PX74-01-06"}
)
)
);
*/
dt = Current Data Table();
Summarize(dt, uniqProd = by(:ProductName));
newVals = Associative Array();
For Each({prodname_str}, uniqProd,
prodPart = Word(1, prodname_str, "_-");
serialPart = Substr(prodname_str, Length(prodPart) + 2);
//find and remove next range from serialPart
newVals[prodname_str] = {};
While(Length(serialPart) > 0 & serialPart != "_" & serialPart != "-",
nextRange = Regex(serialPart, "\d*-\d*");
If(IsMissing(nextRange),
break();
);
serialPart = Substitute(serialPart, nextRange, "");
If(Contains({"-", "_" }, Substr(serialPart, 1, 1)),
serialPart = Substr(serialPart, 2); //remove -_ if first character
);
nextRange = Words(nextRange, "-");
rangeVals = Index(Num(nextRange[1]), Num(nextRange[2]));
For Each({val}, rangeVals,
val = char(val);
val = Substr("00", Length(val) + 1) || val;
Insert Into(newVals[prodname_str], prodPart||"-"||val);
);
);
singleVals = Transform Each({val}, Words(serialPart, "_"),
val = char(val);
val = Substr("00", Length(val) + 1) || val;
prodPart||"-"||val;
);
Insert Into(newVals[prodname_str], singleVals);
);
vals = {{}, {}};
For Each({{key, value}}, newVals,
productname_list = Repeat({key}, N Items(value));
Insert Into(vals[1], productname_list);
Insert Into(vals[2], Sort List(value));
);
//add values to new table
dt = New Table("Productname",
New Column("ProductName", Character, "Nominal", Set Values({})),
New Column("OUTPUT", Character, "Nominal", Set Values({}))
);
dt:ProductName << Set Values(vals[1]);
dt:OUTPUT << Set Values(vals[2]);
Re: Analizar cadena de una columna y llenar otra columnaSimplemente tuvo un error menor en el que no se eliminó un -1 cuando reestructuré mi código.

Names Default To Here( 1 );
dt = Current Data Table();
dt2 = New Table( "The Output",
New Column( "Product Name", character ),
New Column( "ProductID", Character ),
New Column( "OUTPUT", Character )
);
For( dtRow = 1, dtRow <= N Rows( dt ), dtRow++,
If( dtRow == 1 | dt:ProductName[dtRow - 1] != dt:ProductName[dtRow],
prodID = Word( 1, dt:ProductName[dtRow], "_" );
remainder = Substr( dt:ProductName[dtRow], Length( prodID ) + 2 );
While( Word( 1, remainder, "_" ) != "",
theWord = Word( 1, remainder, "_" );
If( Contains( theWord, "-" ),
numDigets = Length( Word( 1, theWord, "-" ) ) - 1;
zeros = Repeat( "0", numDigets );
For( loop = Num( Word( 1, theWord, "-" ) ),
loop <= Num( Word( 2, theWord, "-" ) ), loop++,
dt2 << Add rows( 1 );
theRow = N Rows( dt2 );
dt2:ProductName[theRow] = dt:ProductName[dtRow];
dt2:ProductID[theRow] = Word( 1, dt:ProductName[dtRow], "_-" );
dt2:output[theRow] = dt2:ProductID[theRow] || "-" ||
Substr( zeros, Length( Char( loop ) ) ) || Char( loop );
);
,
dt2 << Add Rows( 1 );
theRow = N Rows( dt2 );
dt2:output[theRow] = prodID || "-" || Word( 1, theWord, "-" );
dt2:ProductName[theRow] = dt:ProductName[dtRow];
dt2:ProductID[theRow] = Word( 1, dt:ProductName[dtRow], "_-" );
);
remainder = Substr( remainder, Length( theWord ) + 2 );
);
)
);
Asegúrese de tomarse el tiempo para estudiar el código para comprender completamente cómo funciona.
Re: Analizar cadena de una columna y llenar otra columnaGracias Jim, pero la SALIDA parece ser incorrecta. Por ejemplo, las primeras 3 líneas, la SALIDA debería ser:
AABBCC-07
AABBCC-08
AABBCC-13
Re: Analizar cadena de una columna y llenar otra columnaLos datos de ProductName se ingresan manualmente. Estas son excepciones y mejorarán con el tiempo. Por favor ignoralos.
Re: Analizar cadena de una columna y llenar otra columnaAquí hay un script que produce una nueva tabla que expande las filas según lo solicitado.Al colocar los datos en una nueva tabla, se evita el problema de que no hay un número suficiente de filas para la expansión.Parece manejar todos los patrones conocidos.

Names Default To Here( 1 );
dt = Current Data Table();
dt2 = New Table( "The Output",
New Column( "Product Name", character ),
New Column( "ProductID", Character ),
New Column( "OUTPUT", Character )
);
For( dtRow = 1, dtRow <= N Rows( dt ), dtRow++,
If( dtRow == 1 | dt:ProductName[dtRow - 1] != dt:ProductName[dtRow],
prodID = Word( 1, dt:ProductName[dtRow], "_" );
remainder = Substr( dt:ProductName[dtRow], Length( prodID ) + 2 );
While( Word( 1, remainder, "_" ) != "",
theWord = Word( 1, remainder, "_" );
If( Contains( theWord, "-" ),
numDigets = Length( Word( 1, theWord, "-" ) ) - 1;
zeros = Repeat( "0", numDigets );
For( loop = Num( Word( 1, theWord, "-" ) ) + 1,
loop <= Num( Word( 2, theWord, "-" ) ), loop++,
dt2 << Add rows( 1 );
theRow = N Rows( dt2 );
dt2:ProductName[theRow] = dt:ProductName[dtRow];
dt2:ProductID[theRow] = Word( 1, dt:ProductName[dtRow], "_-" );
dt2:output[theRow] = dt2:ProductID[theRow] || "-" ||
Substr( zeros, Length( Char( loop ) ) ) || Char( loop );
);
,
dt2 << Add Rows( 1 );
theRow = N Rows( dt2 );
dt2:output[theRow] = prodID || "-" || Word( 1, theWord, "-" );
dt2:ProductName[theRow] = dt:ProductName[dtRow];
dt2:ProductID[theRow] = Word( 1, dt:ProductName[dtRow], "_-" );
);
remainder = Substr( remainder, Length( theWord ) + 2 );
);
)
);Re: Analizar cadena de una columna y llenar otra columnaComprobando rápidamente hay tres problemas diferentes:
1. Romper la "regla" de que siempre hay la misma cantidad de nombres de productos que deberían ser publicaciones seriadas. N4TA59_13-19 en datos solo una vez, debería ser 7 veces
2. La parte del número de serie no comienza con _ (N4PX74 - 01-06)
3. El rango no comienza con _ (N4TA47_13-14-15-16-17-18) o estos deben ser solo valores únicos
Todo esto requerirá diferentes soluciones. ¿Son estos problemas de calidad de los datos con sus datos o el script debería poder manejarlos todos?
Re: Analizar cadena de una columna y llenar otra columnaHola jthi,
Su script no funcionará si mi ProductName es una combinación de caracteres y números. Adjunté una tabla. Así es como se verá la mayor parte de mi nombre de producto. Gracias por ayudarme.
Re: Analizar cadena de una columna y llenar otra columnaSi ese es el caso, ya debería poder manejarlo. Hice pequeñas modificaciones (creación de la columna SALIDA si falta). Actualmente, se basa en el hecho de que la tabla de datos está ordenada por Nombres de productos, lo que podría causar problemas en algún momento, o luego puede asegurarse de que la tabla de entrada esté ordenada (solución más fácil).
Debería poder usar la parte For Each, incluso se puede usar sin la tabla de datos siempre que tenga una variable de lista llamada uniqProd que tenga ProductNames. Después de eso, solo queda descubrir cómo agregar valores a la tabla de datos.
Names Default To Here(1);
//Test table
/*
dt = New Table("Untitled 4993",
Compress File When Saved(1),
New Column("ProductName",
Character,
"Nominal",
Set Values(
{"AABBCC_07-08_13", "AABBCC_07-08_13", "AABBCC_07-08_13", "AABBCC_09-12", "AABBCC_09-12", "AABBCC_09-12", "AABBCC_09-12", "EEFFGG_02",
"HHIIJJ_01-07", "HHIIJJ_01-07", "HHIIJJ_01-07", "HHIIJJ_01-07", "HHIIJJ_01-07", "HHIIJJ_01-07", "HHIIJJ_01-07", "KKLLLMM_01-03_05-08",
"KKLLLMM_01-03_05-08", "KKLLLMM_01-03_05-08", "KKLLLMM_01-03_05-08", "KKLLLMM_01-03_05-08", "KKLLLMM_01-03_05-08", "KKLLLMM_01-03_05-08",
"NNOOPP_01_04_05-08", "NNOOPP_01_04_05-08", "NNOOPP_01_04_05-08", "NNOOPP_01_04_05-08", "NNOOPP_01_04_05-08", "NNOOPP_01_04_05-08",
"QQRRSS_09_11_13_14", "QQRRSS_09_11_13_14", "QQRRSS_09_11_13_14", "QQRRSS_09_11_13_14"}
)
)
);
*/
dt = Current Data Table();
Summarize(dt, uniqProd = by(:ProductName));
valList = {};
For Each({prod}, uniqProd, //loop for each ProductName
prodPart = Word(1, prod, "_");
serialPart = Substr(prod, Contains(prod, "_") + 1); //remove start
possibleRanges = Words(serialPart, "_"); //if they contain -
For Each({val}, possibleRanges, //Loop for serialnumber inside the ProductName
If(Contains(val, "-"), //range
rangeVals = Words(val, "-");
For Each({val1}, Index(Num(rangeVals[1]), Num(rangeVals[2])),
valToAdd = Substr("0", Length(Char(val1))) || Char(val1);
Insert Into(valList, prodPart || "-" || valToAdd)
);
,
Insert Into(valList, prodPart || "-" || Substr("0", Length(Char(val))) || Char(val))
)
);
);
//if starting table doesn't have OUTPUT column create it
If(!Contains(dt << Get Column Names("String"), "OUTPUT"),
dt << New Column("OUTPUT", Character, "Nominal");
);
//dt[0,"OUTPUT"] = valList; subscripting, maybe a bit more difficult to understand
dt:OUTPUT << Set Values(valList);
Versión simplificada de lo que intenta hacer el script:
1. El script obtiene todos los valores únicos en la columna ProductName
2. El script recorre cada uno de los bucles For Each de dos partes.
3. El primer bucle recorre los valores únicos y los divide en Producto y partes numéricas.
4. La parte del número de serie se repite nuevamente para dividirla en valores únicos. Estos valores únicos se concatenan con la parte Producto y luego la cadena se inserta en la lista valList (esto 4. no es exactamente tan simple como expliqué aquí).
5. Una vez finalizados ambos ciclos, debería tener una lista con todos los números de serie posibles. La parte del producto estará en orden alfabético.
6. Esta lista luego se agrega a SALIDA si existe; si no existe, se crea primero.
Re: Analizar cadena de una columna y llenar otra columnaHola jthi,
Sí, el número de filas coincidió con el número de números de serie.
Re: Analizar cadena de una columna y llenar otra columnaDebería ser bastante fácil. ¿Tiene tantas filas en los datos extraídos como números de serie?
Re: Analizar cadena de una columna y llenar otra columnaHola jthi,
Gracias por el guión, pero mi tabla es realmente dinámica. Cada día, extraeré esta tabla de una base de datos con un rango de fechas diferente y aparecerán diferentes conjuntos de ProductName. Entonces no siempre son 32 filas. Su secuencia de comandos casi puede funcionar, pero ¿puede abordar el tamaño de la matriz? Gracias.
Re: Analizar cadena de una columna y llenar otra columnaHola Chris,
Tengo una secuencia de comandos que abordará algunos de los nombres de productos y, a veces, se analizará incorrectamente. ¿Puedes revisar y agregar códigos para abordar aquellos nombres de productos que no funcionan hasta ahora?
Funcionará para los siguientes ejemplos:
EEFFGG_02
HHIIJJ_01-07
KKLLLMM_01-03_05-08
No funcionará todavía para los siguientes ejemplos:
AABBCC_07-08_13
NNOOPP_01_04_05-08
QQRRSS_09_11_13_14
dt=current data table();
(dt << New Column( "ProductID", Character )) << Set Selected;
(dt << New Column( "OUTPUT", Character )) << Set Selected;
//Parse string in ProductName column
For Each Row(
dt,
//Assign the ProductID value
:ProductID = Word( 1, :ProductName, "_-" ); //"_"
//If the ProductName changes, capture the start and end
If( :ProductName != Lag( :ProductName, 1 ),
start = Num( Word( 2, :ProductName, "_-" ) );
end = Num( Word( 3, :ProductName, "_-" ) );
);
//Assign the OUTPUT value
:OUTPUT = :ProductID || "-" || Repeat( "0", 2 - Length( Char( start ) ) ) || Char( start );
//After end value & there is an _, set start to value after _
If( start == end & Contains( :ProductName, "_"),
start = Num( Word(-2, :ProductName, "_-" ) ),
start++);
);
Re: Analizar cadena de una columna y llenar otra columnaBien, esto podría funcionar. Requiere JMP16 debido al uso de For Each (se puede reemplazar con For para otras versiones). Esta es una solución con muchos scripts, con pocos o ningún comentario y requerirá una tabla de inicio específica para funcionar (necesita la columna SALIDA).
Names Default To Here(1);
dt = New Table("Untitled 4993",
Add Rows(32),
Compress File When Saved(1),
New Column("ProductName",
Character,
"Nominal",
Set Values(
{"AABBCC_07-08_13", "AABBCC_07-08_13", "AABBCC_07-08_13", "AABBCC_09-12", "AABBCC_09-12", "AABBCC_09-12", "AABBCC_09-12", "EEFFGG_02",
"HHIIJJ_01-07", "HHIIJJ_01-07", "HHIIJJ_01-07", "HHIIJJ_01-07", "HHIIJJ_01-07", "HHIIJJ_01-07", "HHIIJJ_01-07", "KKLLLMM_01-03_05-08",
"KKLLLMM_01-03_05-08", "KKLLLMM_01-03_05-08", "KKLLLMM_01-03_05-08", "KKLLLMM_01-03_05-08", "KKLLLMM_01-03_05-08", "KKLLLMM_01-03_05-08",
"NNOOPP_01_04_05-08", "NNOOPP_01_04_05-08", "NNOOPP_01_04_05-08", "NNOOPP_01_04_05-08", "NNOOPP_01_04_05-08", "NNOOPP_01_04_05-08",
"QQRRSS_09_11_13_14", "QQRRSS_09_11_13_14", "QQRRSS_09_11_13_14", "QQRRSS_09_11_13_14"}
)
),
New Column("OUTPUT",
Character(16),
"Nominal",
Set Values({"", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", ""})
)
);
Summarize(dt, uniqProd = by(:ProductName));
valList = {};
For Each({prod}, uniqProd,
prodPart = Word(1, prod, "_");
serialPart = Substr(prod, Contains(prod, "_") + 1); //remove start
possibleRanges = Words(serialPart, "_"); //if they contain -
For Each({val}, possibleRanges,
If(Contains(val, "-"), //range
rangeVals = Words(val, "-");
For Each({val1}, Index(Num(rangeVals[1]), Num(rangeVals[2])),
valToAdd = Substr("0", Length(Char(val1))) || Char(val1);
Insert Into(valList, prodPart || "-" || valToAdd)
);
,
Insert Into(valList, prodPart || "-" || Substr("0", Length(Char(val))) || Char(val))
)
);
);
dt[0,"OUTPUT"] = valList;Me pregunto si algo como esto podría hacerse "fácilmente" con la coincidencia de patrones propia de JMP. @Craige_Hales
Re: Analizar cadena de una columna y llenar otra columnaGracias, pero prefiero un jsl en lugar del delimitador interactivo. Su método no abordó el escenario cuando el número de serie 09-12. Debería generar filas como las que se muestran a continuación. No sólo AABBCC-09 y AABBCC-12. El "-" significa "hasta", lo que significa rango. Entonces 09-12 significa 09, 10, 11, 12.
| AABBCC_09-12 | AABBCC-09 |
| AABBCC_09-12 | AABBCC-10 |
| AABBCC_09-12 | AABBCC-11 |
| AABBCC_09-12 | AABBCC-12 |
Re: Analizar cadena de una columna y llenar otra columnaAh, tienes razón. el - se interpreta como un rango y el _ se interpreta como un verdadero delimitador de elementos
Re: Analizar cadena de una columna y llenar otra columna@jthi ,
Me ganaste.
Tu explicación es más detallada y en lo que estaba pensando también.
Re: Analizar cadena de una columna y llenar otra columnaHola @cchueng ,
Hay un par de maneras. Algunos son una base de secuencias de comandos (busque una respuesta de alguien que sugiera esto con un ejemplo) o puede usar rondas sucesivas de Texto a columnas (el ejemplo se encuentra aquí Resuelto: ¿Cómo puedo dividir el texto de una columna en varias columnas? - Comunidad de usuarios de JMP) Luego, puede concatenar las columnas deseadas seleccionándolas y luego usar una fórmula de columna o usar la opción Nueva columna de fórmula después de hacer clic derecho en una de las columnas seleccionadas. Busque las opciones de caracteres para concat.La fórmula de la columna es más flexible y le brinda muchas opciones; consulte la ayuda sobre este tema ( Crear fórmulas en JMP )
Espero que eso te dé alguna dirección.
Mejor,
Re: Analizar cadena de una columna y llenar otra columnaLo más probable es que puedas escribir una fórmula con Lag para hacerlo (o un script con JSL), pero también puedes intentar hacerlo de forma interactiva, pero requiere bastantes pasos:
1. Seleccione la columna Nombre del producto
2. Vaya a las columnas Cols/Utilities/Text To y use tanto - como _ como delimitadores

3. Vaya a Tablas y apilar y agregue todo lo demás además de la primera columna a la selección de Apilar columnas.


5. Eliminar columna de etiqueta
6. Seleccione las dos columnas que quedan y vaya a Filas/Selección de filas/Seleccione Duplicar filas y elimine esas filas.

7. Seleccione una celda con valor vacío y elija Seleccionar celdas coincidentes y elimine esas filas.
8. Ahora elija ambas columnas y haga clic derecho en el encabezado de la columna y cree la fórmula.

9. Abra la fórmula recién creada y cambie , a _

10. Cambiar el nombre y eliminar columnas/fórmulas
11. Si necesitas tener ProductName allí, deberías poder conservarlo allí si no lo eliminas accidentalmente en el primer paso como lo hice yo.

Si tiene que tener - o _ dependiendo del número de serie, lo más probable es que pueda manejarlo en la fórmula de concatenación
Editar: revisé la pregunta con un poco más de precisión y esto es un poco más complicado de lo que mostré aquí. Tendrá que agregar cálculos para algunos de los números de serie porque están entre números. Esta solución no funcionará en ellos porque algunas filas se eliminarán cuando se eliminen los duplicados.