열의 문자열을 구문 분석하고 다른 열을 채웁니다.안녕,
ProductName이 포함된 테이블이 있고 OUTPUT 열을 생성하려고 합니다.OUTPUT 열은 ProductID와 Serial#을 연결한 것입니다. Serial#을 정확하게 구문 분석하고 OUTPUT 열을 생성하려면 어떻게 해야 합니까?
일련번호 예:
- 07-08_13은 일련번호 07, 08, 13을 의미합니다.
- 09-12는 일련번호 09, 10, 11, 12를 의미합니다.
- 01-03_05-08은 일련 번호 01, 02, 03, 05, 06, 07, 08을 의미합니다.
- 01_04_05-08은 일련 번호 01, 04, 05, 06, 07, 08을 의미합니다.
- 09_11_13_14는 일련 번호 09,11,13,14를 의미합니다.

| 상품명 | 산출 |
| 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 |
고급 통계 모델링대량 맞춤화Re: 열의 문자열을 구문 분석하고 다른 열을 채웁니다.예, 가능합니다. 하지만 언제 새 행을 추가할지 등에 대한 논리를 마련해야 합니다.내가 제안하는 것은 당신이 하는 일은 코드를 있는 그대로 실행하고 다음을 사용하는 것입니다.
테이블=>조인
2개의 데이터 테이블을 하나로 합칩니다.
Re: 열의 문자열을 구문 분석하고 다른 열을 채웁니다.안녕하세요 짐,
dt2가 없도록 할 수 있습니까? dt에 ProductID 및 Output 열을 추가할 수 있나요?
감사해요!
Re: 열의 문자열을 구문 분석하고 다른 열을 채웁니다.데이터를 수동으로 입력했기 때문에 모든 특수한 경우를 처리할 수는 없지만 현재 값에서는 작동하는 것 같습니다.
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: 열의 문자열을 구문 분석하고 다른 열을 채웁니다.코드를 재구성할 때 -1이 제거되지 않는 사소한 오류가 있었습니다.

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 );
);
)
);
시간을 내어 코드를 연구하여 코드가 어떻게 작동하는지 완전히 이해하시기 바랍니다.
Re: 열의 문자열을 구문 분석하고 다른 열을 채웁니다.Jim에게 감사합니다. 하지만 OUTPUT이 잘못된 것 같습니다. 예를 들어 처음 3줄의 OUTPUT은 다음과 같아야 합니다.
AABBCC-07
AABBCC-08
AABBCC-13
Re: 열의 문자열을 구문 분석하고 다른 열을 채웁니다.ProductName 데이터는 수동으로 입력됩니다. 이는 예외이며 시간이 지나면서 개선될 것입니다. 무시해 주세요.
Re: 열의 문자열을 구문 분석하고 다른 열을 채웁니다.다음은 요청에 따라 행을 확장하는 새 테이블을 생성하는 스크립트입니다.데이터를 새 테이블에 배치함으로써 확장에 필요한 행 수가 충분하지 않은 문제를 우회합니다.알려진 모든 패턴을 처리하는 것으로 보입니다.

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: 열의 문자열을 구문 분석하고 다른 열을 채웁니다.세 가지 다른 문제가 있는지 빠르게 확인하세요.
1. 연재물과 항상 동일한 양의 ProductName이 있다는 "규칙"을 깨뜨립니다. N4TA59_13-19는 데이터에 한 번만 포함되며 7번이어야 합니다.
2. 일련번호 부분이 _로 시작하지 않음 (N4PX74 - 01-06)
삼. 범위가 _(N4TA47_13-14-15-16-17-18)로 시작하지 않거나 단일 값이어야 합니다.
이 모든 것에는 다른 수정이 필요합니다. 데이터에 이러한 데이터 품질 문제가 있습니까? 아니면 스크립트가 이러한 모든 문제를 처리할 수 있어야 합니까?
Re: 열의 문자열을 구문 분석하고 다른 열을 채웁니다.안녕하세요 jthi 님,
내 ProductName에 문자와 숫자가 혼합되어 있으면 스크립트가 작동하지 않습니다. 표를 첨부했어요. 내 productName의 대부분은 다음과 같습니다. 도와주셔서 감사합니다.
Re: 열의 문자열을 구문 분석하고 다른 열을 채웁니다.그렇다면 이미 처리할 수 있어야 합니다. 약간의 수정을 했습니다(누락된 경우 OUTPUT 열 생성). 현재는 데이터 테이블이 ProductNames별로 정렬되어 있어 어느 시점에서 문제가 발생할 수 있다는 사실에 의존합니다. 그런 다음 입력 테이블이 정렬되었는지 확인할 수 있습니다(가장 쉬운 솔루션).
ProductNames가 있는 uniqProd라는 목록 변수가 있는 한 데이터 테이블 없이도 For Each 부분을 사용할 수 있습니다. 그 후에는 데이터 테이블에 값을 추가하는 방법을 알아내는 것입니다.
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);
스크립트가 수행하려는 작업을 단순화한 버전:
1. 스크립트는 ProductName 열의 모든 고유 값을 가져옵니다.
2. For Each 루프의 두 부분으로 구성된 각 항목에 대한 스크립트 루프
3. 첫 번째 루프는 고유 값을 반복하여 이를 제품 및 숫자 부분으로 분할합니다.
4. 그런 다음 일련번호 부분이 다시 반복되어 단일 값으로 분할됩니다. 이러한 단일 값은 Product 부분과 연결된 다음 문자열이 valList 목록에 삽입됩니다(이 4.는 여기서 설명한 것만큼 간단하지 않습니다).
5. 두 루프가 모두 완료되면 가능한 모든 일련번호가 포함된 목록이 생성됩니다. 제품 부분은 알파벳 순서로 되어 있습니다.
6. 이 목록이 있으면 OUTPUT에 추가되고, 없으면 먼저 생성됩니다.
Re: 열의 문자열을 구문 분석하고 다른 열을 채웁니다.안녕하세요 jthi 님,
예, 행 수가 일련번호와 일치했습니다.
Re: 열의 문자열을 구문 분석하고 다른 열을 채웁니다.꽤 쉬울 것입니다. 가져온 데이터에 일련 번호만큼 많은 행이 있습니까?
Re: 열의 문자열을 구문 분석하고 다른 열을 채웁니다.안녕하세요 jthi 님,
스크립트를 작성해 주셔서 감사합니다. 하지만 내 테이블은 실제로 동적입니다. 매일 다른 날짜 범위의 데이터베이스에서 이 테이블을 가져오며 다른 ProductName 집합이 표시됩니다. 따라서 항상 32개 행은 아닙니다. 스크립트는 거의 작동하지만 배열 크기를 해결할 수 있습니까? 감사해요.
Re: 열의 문자열을 구문 분석하고 다른 열을 채웁니다.안녕하세요 크리스,
ProductName의 일부를 처리하고 때로는 잘못 구문 분석하는 스크립트가 있습니다. 지금까지 작동하지 않는 ProductName을 해결하기 위해 코드를 검토하고 추가할 수 있습니까?
아래 예에서 작동합니다.
EEFFGG_02
HHIIJJ_01-07
KKLLLMM_01-03_05-08
아래 예에서는 아직 작동하지 않습니다.
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: 열의 문자열을 구문 분석하고 다른 열을 채웁니다.좋아, 이게 효과가 있을 것 같아. For Each 사용으로 인해 JMP16이 필요합니다(다른 버전의 경우 For로 대체 가능). 이것은 설명이 거의 없거나 전혀 없는 스크립트 기반 솔루션이며 작동하려면 특정 시작 테이블이 필요합니다(OUTPUT 열 필요).
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;JMP의 자체 패턴 일치를 사용하여 이와 같은 작업을 "쉽게" 수행할 수 있는지 궁금합니다. @Craige_Hales
Re: 열의 문자열을 구문 분석하고 다른 열을 채웁니다.고맙지만 대화형 구분 기호보다는 jsl을 선호합니다. 귀하의 방법은 일련 번호가 표시된 시나리오를 해결하지 못했습니다. 09-12. 아래와 같은 행이 출력되어야 합니다. AABBCC-09와 AABBCC-12만이 아닙니다. "-"는 범위를 의미하는 "~"를 의미합니다. 따라서 09-12는 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: 열의 문자열을 구문 분석하고 다른 열을 채웁니다.아, 그렇군요. -는 범위로 해석되고 _는 항목의 실제 구분 기호로 해석됩니다.
Re: 열의 문자열을 구문 분석하고 다른 열을 채웁니다.@jthi ,
당신이 나를 이겼어요.
설명이 더 자세하고 제가 생각했던 내용도 그렇네요.
Re: 열의 문자열을 구문 분석하고 다른 열을 채웁니다.안녕 @cchueng ,
몇 가지 방법이 있습니다. 일부는 스크립팅 기반입니다(예를 들어 이를 제안하는 사람의 답변을 찾아보세요). 또는 연속적인 텍스트 대 열을 사용할 수 있습니다(예는 여기에서 찾을 수 있음). 해결: 한 열의 텍스트를 여러 열로 분할하려면 어떻게 해야 합니까? - JMP 사용자 커뮤니티) 그런 다음 원하는 열을 선택하여 연결한 다음 열 수식을 사용하거나 선택한 열 중 하나를 마우스 오른쪽 버튼으로 클릭한 후 새 수식 열 옵션을 사용할 수 있습니다. concat에 대한 문자 옵션을 찾으십시오.열 수식은 더 유연하며 다양한 옵션을 제공합니다. 이 항목에 대한 도움말을 참조하세요( JMP에서 공식 생성 )
그것이 당신에게 어떤 방향을 제시해주기를 바랍니다.
최상의,
Re: 열의 문자열을 구문 분석하고 다른 열을 채웁니다.이를 수행하기 위해 Lag를 사용하여 공식을 작성할 수도 있지만(또는 JSL을 사용하여 스크립트) 이를 대화식으로 시도할 수도 있지만 몇 가지 단계가 필요합니다.
1. ProductName 열을 선택합니다.
2. Cols/Utilities/Text To columns로 이동하여 -와 _를 구분 기호로 사용합니다.

3. 테이블 및 스택으로 이동하여 첫 번째 열 이외의 모든 항목을 스택 열 선택에 추가합니다.


5. 라벨 열 제거
6. 왼쪽 열을 모두 선택하고 행 / 행 선택 / 중복 행 선택으로 이동하여 해당 행을 삭제하십시오.

7. 값이 비어 있는 셀 하나를 선택하고 일치하는 셀 선택을 선택하고 해당 행을 삭제합니다.
8. 이제 두 열을 모두 선택하고 열 머리글을 마우스 오른쪽 버튼으로 클릭한 후 수식을 만듭니다.

9. 방금 생성된 수식을 열고 ,를 _로 변경합니다.

10. 열/수식 이름 바꾸기 및 삭제
11. 꼭 필요한 경우 거기에 ProductName이 있습니다. 저처럼 첫 번째 단계에서 실수로 삭제하지 않는 한 거기에 보관할 수 있습니다.

일련 번호에 따라 - 또는 _가 있어야 하는 경우 연결 수식에서 처리할 수 있습니다.
편집: 질문을 좀 더 정확하게 확인했는데 여기에 표시된 것보다 조금 더 복잡합니다. 일련번호 중 일부는 숫자 사이에 있으므로 계산을 추가해야 합니다. 중복 항목이 제거되면 일부 행이 제거되므로 이 솔루션은 작동하지 않습니다.