본문으로 건너뛰기

"kata" 태그로 연결된 63개 게시물개의 게시물이 있습니다.

모든 태그 보기

· 약 5분
karais89

Instructions

링크

Short Intro

Some of you might remember spending afternoons playing Street Fighter 2 in some Arcade back in the 90s or emulating it nowadays with the numerous emulators for retro consoles.

Can you solve this kata? Suuure-You-Can!

UPDATE: a new kata's harder version is available here.

The Kata

You'll have to simulate the video game's character selection screen behaviour, more specifically the selection grid. Such screen looks like this:

Selection Grid Layout in text:

| Ryu | E.Honda | Blanka | Guile | Balrog | Vega |
| Ken | Chun Li | Zangief | Dhalsim | Sagat | M.Bison |

Input

  • the list of game characters in a 2x6 grid;
  • the initial position of the selection cursor (top-left is (0,0));
  • a list of moves of the selection cursor (which are up, down, left, right);

Output

  • the list of characters who have been hovered by the selection cursor after all the moves (ordered and with repetition, all the ones after a move, wether successful or not, see tests);

Rules

Selection cursor is circular horizontally but not vertically!

As you might remember from the game, the selection cursor rotates horizontally but not vertically; that means that if I'm in the leftmost and I try to go left again I'll get to the rightmost (examples: from Ryu to Vega, from Ken to M.Bison) and vice versa from rightmost to leftmost.

Instead, if I try to go further up from the upmost or further down from the downmost, I'll just stay where I am located (examples: you can't go lower than lowest row: Ken, Chun Li, Zangief, Dhalsim, Sagat and M.Bison in the above image; you can't go upper than highest row: Ryu, E.Honda, Blanka, Guile, Balrog and Vega in the above image).

Test

For this easy version the fighters grid layout and the initial position will always be the same in all tests, only the list of moves change.

Notice : changing some of the input data might not help you.

Examples

fighters = [
["Ryu", "E.Honda", "Blanka", "Guile", "Balrog", "Vega"],
["Ken", "Chun Li", "Zangief", "Dhalsim", "Sagat", "M.Bison"]
]
initial_position = (0,0)
moves = ['up', 'left', 'right', 'left', 'left']

then I should get:

['Ryu', 'Vega', 'Ryu', 'Vega', 'Balrog']

as the characters I've been hovering with the selection cursor during my moves. Notice: Ryu is the first just because it "fails" the first up See test cases for more examples.

fighters = [
["Ryu", "E.Honda", "Blanka", "Guile", "Balrog", "Vega"],
["Ken", "Chun Li", "Zangief", "Dhalsim", "Sagat", "M.Bison"]
]
initial_position = (0,0)
moves = ['right', 'down', 'left', 'left', 'left', 'left', 'right']

Result:

['E.Honda', 'Chun Li', 'Ken', 'M.Bison', 'Sagat', 'Dhalsim', 'Sagat']

OFF-TOPIC

Some music to get in the mood for this kata :

Street Fighter 2 - selection theme

My Solution

using System;
using System.Collections.Generic;
using System.Linq;

public class Kata
{
public string[] StreetFighterSelection(string[][] fighters, int[] position, string[] moves)
{
int col = fighters.Length;
int row = fighters[0].Length;

int curCol = position[0];
int curRow = position[1];

List<string> charTracking = new List<string>();
for (int i = 0; i < moves.Length; i++)
{
int moveCol;
int moveRow;
switch (moves[i])
{
case "up":
moveCol = curCol - 1;
if (moveCol >= 0)
{
curCol = moveCol;
}
break;
case "down":
moveCol = curCol + 1;
if (moveCol < col)
{
curCol = moveCol;
}
break;
case "left":
moveRow = curRow - 1;
curRow = moveRow < 0 ? row - 1 : moveRow;
break;
case "right":
moveRow = curRow + 1;
curRow = moveRow > row - 1 ? 0 : moveRow;
break;
}
charTracking.Add(fighters[curCol][curRow]);
}
return charTracking.ToArray();
}
}
  • 게임 캐릭터의 리스트는 2x6 그리드 이다.
  • 선택 커서의 초기 위치는 0,0 이다.
  • 선택 커서는 위, 아래, 좌, 우로 이동할 수 있다.
  • 커서의 순환은 (양 옆 혹은 위) 수평으로만 가능 하다.

Best Practices

using System;
using System.Collections.Generic;
using System.Linq;

public class Kata
{
public string[] StreetFighterSelection(string[][] fighters, int[] position, string[] moves)
{
var results = new List<string>();
var row = 0;
var col = 0;

foreach (var s in moves) {
switch (s) {
case "up": row -= 1;
break;
case "down": row += 1;
break;
case "left": col -= 1;
break;
case "right": col += 1;
break;
}
if (row < 0) row = 0;
if (row == fighters.Length) row--;
if (col == fighters[0].Length) col = 0;
if (col == -1) col = fighters[0].Length - 1;

results.Add(fighters[row][col]);
}

return results.ToArray();
}
}

거의 유사하지만, 범위 체크를 맨 아래에서 해주었다. 범위체크를 움직일때마다 해주는 것보다 맨 마지막에 해주는게 깔끔한 느낌도 든다.

· 약 3분
karais89

Instructions

링크

The input is a string str of digits. Cut the string into chunks (a chunk here is a substring of the initial string) of size sz (ignore the last chunk if its size is less than sz).

If a chunk represents an integer such as the sum of the cubes of its digits is divisible by 2, reverse that chunk; otherwise rotate it to the left by one position. Put together these modified chunks and return the result as a string.

If

  • sz is <= 0 or if str is empty return ""
  • sz is greater (>) than the length of str it is impossible to take a chunk of size sz hence return "".

Examples:

revrot("123456987654", 6) --> "234561876549"
revrot("123456987653", 6) --> "234561356789"
revrot("66443875", 4) --> "44668753"
revrot("66443875", 8) --> "64438756"
revrot("664438769", 8) --> "67834466"
revrot("123456779", 8) --> "23456771"
revrot("", 8) --> ""
revrot("123456779", 0) --> ""
revrot("563000655734469485", 4) --> "0365065073456944"

My Solution

using System;
using System.Text;
using System.Linq;

public class Revrot
{
public static string InternalRevRot(string str)
{
if (String.IsNullOrEmpty(str))
{
return string.Empty;
}

int sum = 0;
for (int i = 0; i < str.Length; i++)
{
sum += int.Parse(str[i].ToString());
}

StringBuilder strBuilder = new StringBuilder();
if (sum % 2 == 0)
{
for (int i = str.Length - 1; i >= 0; i--)
{
strBuilder.Append(str[i]);
}
return strBuilder.ToString();
}

for (int i = 1; i < str.Length; i++)
{
strBuilder.Append(str[i]);
}
strBuilder.Append(str[0]);
return strBuilder.ToString();
}

public static string RevRot(string strng, int sz)
{
if (sz <= 0 || String.IsNullOrEmpty(strng) || strng.Length < sz)
{
return string.Empty;
}

StringBuilder strBuilder = new StringBuilder();
for (int i = 0; i < strng.Length; i += sz)
{
if (i + sz < strng.Length)
{
string str = strng.Substring(i, sz);
strBuilder.Append(InternalRevRot(str));
}
}
return strBuilder.ToString();
}
}

일단 영어 해석이 안되서 헤맸다. 천천히 문제를 다시 읽어 봤다.

주어진 sz 매개변수 만큼 substring으로 문자열을 가르고 각각의 문자열의 합을 기준으로 다음과 같은 기준으로 판단

  1. 문자열의 총 합이 짝수이면 숫자 뒤집기. (1->2->3 순서일때 3->2->1)
  2. 문자열의 합이 홀수이면 왼쪽으로 한칸 이동시키기. (1->2->3 순서일때 2->3->1)

Best Practices

using System;
using System.Linq;

public class Revrot
{
public static string RevRot(string strng, int sz)
{
if (String.IsNullOrEmpty(strng) || sz <= 0 || sz > strng.Length)
return String.Empty;

return
new String(
Enumerable.Range(0, strng.Length/sz)
.Select(i => strng.Substring(i*sz, sz))
.Select(
chunk =>
chunk.Sum(digit => (int) Math.Pow(int.Parse(digit.ToString()), 3))%2 == 0
? chunk.Reverse()
: chunk.Skip(1).Concat(chunk.Take(1)))
.SelectMany(x => x)
.ToArray());
}
}

chunk.Reverse() 이 부분에 해당

      StringBuilder strBuilder = new StringBuilder();
if (sum % 2 == 0)
{
for (int i = str.Length - 1; i >= 0; i--)
{
strBuilder.Append(str[i]);
}
return strBuilder.ToString();
}

chunk.Skip(1).Concat(chunk.Take(1)) 이 부분에 해당

      for (int i = 1; i < str.Length; i++)
{
strBuilder.Append(str[i]);
}
strBuilder.Append(str[0]);
return strBuilder.ToString();

· 약 3분
karais89

Instructions

링크

Task Write a function that accepts msg string and returns local tops of string from the highest to the lowest. The string's tops are from displaying the string in the below way:

When the msg string is empty, return an empty string. The input strings may be very long. Make sure your solution has good performance. Check the test cases for more samples.

Note for C++ Do not post an issue in my solution without checking if your returned string doesn't have some invisible characters. You read most probably outside of msg string.

My Solution

using System;
using System.Text;
using System.Collections.Generic;

public static class Kata
{
public static string Tops(string msg)
{
if (string.IsNullOrEmpty(msg))
{
return string.Empty;
}

int switchCount = 0;
int addNum = 0;
int goalNum = 0;
List<int> topIndexs = new List<int>();
for (int i = 0; i < msg.Length; i++)
{
if (i == goalNum)
{
// switchCount is odd top index
if (switchCount % 2 == 1)
{
topIndexs.Add(i);
}
switchCount++;
addNum++;
goalNum += addNum;
}
}

StringBuilder strBuilder = new StringBuilder();
for (int i = topIndexs.Count - 1; i >= 0; i--)
{
strBuilder.Append(msg[topIndexs[i]]);
}

return strBuilder.ToString();
}
}

공통적으로 증가하는 수가 존재할 것 같다는 생각을 했는데 (수열) 찾지를 못해서, 그냥 가장 큰 수의 인덱스를 저장한 후에 스트링을 뿌려주는 방식으로 처리 하였다.

수열을 찾지 못한 이유는 중간에 계산 실수가 있었다.

Best Practices 1

using System.Text;

public static class Kata
{
public static string Tops(string msg)
{
StringBuilder result = new StringBuilder();

for(int i = 1, x = 0; i < msg.Length; i += 5 + 4 * x, x++)
result.Insert(0, msg[i]);

return result.ToString();
}
}

큰 수의 인덱스 배열 : 1 -> 6 -> 15 -> 28

차이 5, 9, 13

차이 : 5+(4*x) -> 5 -> 9 -> 13

으로 수열이 존재한다.

Best Practices 2

using System;
using System.Linq;
using System.Collections.Generic;


public static class Kata
{
public static string Tops(string msg)
{
int jump = 1;
Stack<char> result = new Stack<char>() { };
for (int i = 1; i < msg.Length; i += jump)
{
if (jump % 2 != 0)
result.Push(msg[i]);
jump += 1;
}
return String.Join("", result);
}

}

나와 생각한 방식은 거의 똑같은데, 훨씬 깔끔하게 처리 하였다.

일단 스트링을 뒤로 뿌려주는 부분을 스택을 통해 처리 하였다. 그리고 추가적으로 내 해결책에서 사용 하던 쓸데없는 변수도 사용하지 않았다.

· 약 2분
karais89

Instructions

Your task is to construct a building which will be a pile of n cubes. The cube at the bottom will have a volume of n^3, the cube above will have volume of (n-1)^3 and so on until the top which will have a volume of 1^3.

You are given the total volume m of the building. Being given m can you find the number n of cubes you will have to build?

The parameter of the function findNb (find_nb, find-nb, findNb) will be an integer m and you have to return the integer n such as n^3 + (n-1)^3 + ... + 1^3 = m if such a n exists or -1 if there is no such n.

Examples:

findNb(1071225) --> 45
findNb(91716553919377) --> -1
mov rdi, 1071225
call find_nb ; rax <-- 45

mov rdi, 91716553919377
call find_nb ; rax <-- -1

My Solution

def find_nb(m):
# your code
sum = 0
count = 0
while True:
count += 1
sum += count**3

if sum == m:
return count

if sum > m:
return -1

c#으로 똑같은 방법으로 풀었는데 테스트 케이스 몇 군데서 계속 에러가 나옴.

codewars 자체가 유저들이 문제를 직접 내고, 테스트 케이스를 작성을 하는 방식이라, 이런식으로 아예 통과를 못하는 경우가 있음.

그냥 넘어가려다가 그냥 파이썬으로 똑같은 방식으로 풀자! 해서 풀었음.

하다 보니 알게 된건 파이썬에서는 증감연산자가 없다는 사실.. (++, --)등

Best Practices

def find_nb(m):
n = 1
volume = 0
while volume < m:
volume += n**3
if volume == m:
return n
n += 1
return -1

거의 비슷한 방식이다.

· 약 2분
karais89

Instructions

Write a function, persistence, that takes in a positive parameter num and returns its multiplicative persistence, which is the number of times you must multiply the digits in num until you reach a single digit.

For example:

 persistence(39) == 3 // because 3*9 = 27, 2*7 = 14, 1*4=4
// and 4 has only one digit

persistence(999) == 4 // because 9*9*9 = 729, 7*2*9 = 126,
// 1*2*6 = 12, and finally 1*2 = 2

persistence(4) == 0 // because 4 is already a one-digit number

My Solution

using System;
using System.Collections.Generic;

public class Persist
{
public static long SumList(List<int> list)
{
long sum = 1;
foreach (int num in list)
{
sum *= num;
}
return sum;
}

public static bool CheckPersistenceList(List<int> list)
{
if (list.Count <= 1)
{
return false;
}

return true;
}

public static int RecusviePersistence(long n, int count)
{
List<int> toInts = new List<int>();
string strNum = n.ToString();
for (int i = 0; i < strNum.Length; i++)
{
toInts.Add(int.Parse(strNum[i].ToString()));
}

long sum = SumList(toInts);
Console.WriteLine("n: " + n + ", sum: " + sum);
if (CheckPersistenceList(toInts))
{
count++;
return RecusviePersistence(sum, count);
}
else
{
return count;
}
}

public static int Persistence(long n)
{
return RecusviePersistence(n, 0);
}
}

뭔가 쓸데 없이 길어지는 느낌..

Best Practices

using System;
using System.Linq;

public class Persist
{
public static int Persistence(long n)
{
int count = 0;
while (n > 9)
{
count++;
n = n.ToString().Select(digit => int.Parse(digit.ToString())).Aggregate((x, y) => x * y);
}
return count;
}
}

Linq 사용

· 약 4분
karais89

Instructions

Given an array of integers of any length, return an array that has 1 added to the value represented by the array.

  • the array can't be empty
  • only non-negative, single digit integers are allowed

Return nil (or your language's equivalent) for invalid inputs.

Examples

For example the array [2, 3, 9] equals 239, adding one would return the array [2, 4, 0].

[4, 3, 2, 5] would return [4, 3, 2, 6]

My Solution

using System;

namespace Kata
{
public static class Kata
{
public static int[] UpArray(int[] num)
{
// invaild check
if (num == null || num.Length == 0)
{
return null;
}

// invalid check
for (int i = 0; i < num.Length; i++)
{
if (num[i] < 0 || num[i] >= 10)
{
return null;
}
}

// array init
int[] arrayOnePlus = new int[num.Length];
for (int i = 0; i < arrayOnePlus.Length; i++)
{
arrayOnePlus[i] = num[i];
}

// one plus array
for (int i = num.Length - 1; i >= 0; i--)
{
int n = num[i] + 1;
if (n != 10)
{
arrayOnePlus[i] = n;
break;
}
else
{
arrayOnePlus[i] = 0;

// array size up..
if (i == 0)
{
int[] newArr = new int[arrayOnePlus.Length + 1];
newArr[0] = 1;
for (int j = 0; j < arrayOnePlus.Length; j++)
{
newArr[j+1] = arrayOnePlus[j];
}

return newArr;
}
}
}

return arrayOnePlus;
}
}
}

원래는 int 배열을 숫자로 바꾼후에 +1을 해주고 int 배열로 다시 만드는 방식으로 구현하려다, 그냥 배열 자체에 값을 구하는 식으로 구현 하였다.

  1. invaild 체크
  2. 인자로 전달 받은 배열을 새 배열에 복사
  3. 각 배열의 인덱스에 +1을 해준다. 그리고 만약 그 합이 10이 넘지 않으면 바로 새 배열의 값을 리턴.
  4. 만약 그 합이 10이 넘는다면 루프를 돌면서 10이 넘지 않을때 까지 반복한다.
  5. 마지막 배열까지 검사를 한 경우에도 10이 넘는 경우면 배열의 길이를 1 증가시켜줘야 되는 경우이므로 1을 증가 시켜준 후에 해당 배열을 다시 만들어 준다음에 리턴 해준다.

Best Practices

using System.Linq;

namespace Kata
{
public static class Kata
{
public static int[] UpArray(int[] num)
{
if (num.Length == 0 || num.Any(a => a < 0 || a > 9))
return null;

for (var i = num.Length - 1; i >= 0; i--)
{
if (num[i] == 9)
{
num[i] = 0;
}
else
{
num[i]++;
return num;
}
}
return new []{ 1 }.Concat(num).ToArray();
}
}
}

구하는 공식은 거의 비슷하지만, 이 코드가 더 짧다. int형 배열의 경우 레퍼런스를 넘겨주기 때문에, 배열 값 자체가 변하는 문제가 있으므로, 배열 값 변경을 원치 않는다면 새로운 배열에 값을 복사해서 진행 하면 될것 같고..

여기서 참고할 부분은 배열의 길이를 1 증가시켜주기 위해 새로 생성해 주는 부분.

int[] newArr = new int[arrayOnePlus.Length + 1];
newArr[0] = 1;
for (int j = 0; j < arrayOnePlus.Length; j++)
{
newArr[j+1] = arrayOnePlus[j];
}
new []{ 1 }.Concat(num).ToArray();

Linq를 사용하면 Concat 메서드를 사용하여 이렇게 간단히 줄일 수 있다는 점은 참고할 만 한 사실이다.

· 약 2분
karais89

Instructions

Some numbers have funny properties. For example:

89 --> 8¹ + 9² = 89 * 1

695 --> 6² + 9³ + 5⁴= 1390 = 695 * 2

46288 --> 4³ + 6⁴+ 2⁵ + 8⁶ + 8⁷ = 2360688 = 46288 * 51

Given a positive integer n written as abcd... (a, b, c, d... being digits) and a positive integer p we want to find a positive integer k, if it exists, such as the sum of the digits of n taken to the successive powers of p is equal to k * n. In other words:

Is there an integer k such as : (a ^ p + b ^ (p+1) + c ^(p+2) + d ^ (p+3) + ...) = n * k

If it is the case we will return k, if not return -1.

Note: n, p will always be given as strictly positive integers.

digPow(89, 1) should return 1 since 8¹ + 9² = 89 = 89 * 1
digPow(92, 1) should return -1 since there is no k such as 9¹ + 2² equals 92 * k
digPow(695, 2) should return 2 since 6² + 9³ + 5⁴= 1390 = 695 * 2
digPow(46288, 3) should return 51 since 4³ + 6⁴+ 2⁵ + 8⁶ + 8⁷ = 2360688 = 46288 * 51

My Solution

using System;

public class DigPow {
public static long digPow(int n, int p) {
string strN = n.ToString();
long sum = 0;
for (int i = 0; i < strN.Length; i++)
{
int digit = int.Parse(strN[i].ToString());
long powVal = (long)Math.Pow(digit, p + i);
sum += powVal;
}

if (sum % n == 0)
{
return sum / n;
}

return -1;
}
}
  1. int형을 String으로 변환
  2. 각 자릿수 대로 제곱 해준후 더해준다.
  3. 더해준 값이 n으로 나누어지면 몫 반환. 아니면 -1 반환

Best Practices

using System.Linq;
using System;

public class DigPow {
public static long digPow(int n, int p) {
var sum = Convert.ToInt64(n.ToString().Select(s => Math.Pow(int.Parse(s.ToString()), p++)).Sum());
return sum % n == 0 ? sum / n : -1;
}
}

Linq는 2줄이면 해결

· 약 3분
karais89

Instructions

Write Number in Expanded Form You will be given a number and you will need to return it as a string in Expanded Form. For example:

Kata.ExpandedForm(12); # Should return "10 + 2"
Kata.ExpandedForm(42); # Should return "40 + 2"
Kata.ExpandedForm(70304); # Should return "70000 + 300 + 4"

NOTE: All numbers will be whole numbers greater than 0.

If you liked this kata, check out part 2!!

My Solution

using System;
using System.Text;

public static class Kata
{
public static string ExpandedForm(long num)
{
// long to string
string strNum = "" + num;
StringBuilder builder = new StringBuilder();
for (int i = 0; i < strNum.Length; i++)
{
if (strNum[i] > '0')
{
if (builder.Length != 0)
{
builder.Append(" + ");
}

// char to string to int
int n = int.Parse(strNum[i].ToString());
double digit = strNum.Length - i - 1;
digit = Math.Pow(10, digit);

string strResult = "" + (n * digit);
builder.Append(strResult);
}
}
return builder.ToString();
}
}

항상 이런 자릿수 문제가 나오면 long형을 string으로 바꾸어 준다음에 풀면 쉽게 풀 수 있다.

builder를 사용하여 풀었고, 저번에 문제를 풀다 보니 맨 처음에만 검사를 해서 기호를 넣어주면 쉽게 해결이 되는 부분이 있어서 그게 생각나서 그렇게 풀어 봤다.

[Codewars #13] Help the bookseller (6kyu) Best Practices 2에서 사용한 방식

Best Practices 1

using System;
using System.Linq;

public static class Kata
{
public static string ExpandedForm(long num)
{
var str = num.ToString();
return String.Join(" + ", str
.Select((x, i) => char.GetNumericValue(x) * Math.Pow(10, str.Length - i - 1))
.Where(x => x > 0));
}
}

Linq를 사용하여 간단히 해결!

string에 있는 0 보다 큰 모든 값을 전부 자릿수대로 곱해주고 그 값을 조인 시켜 구한다.

Best Practices 2

using System;
using System.Collections.Generic;

public static class Kata
{
public static string ExpandedForm(long num)
{
Stack<long> parts = new Stack<long>();

for (long m = 1, n = num; n > 0; n /= 10, m *= 10)
{
long digit = n % 10;
if (digit > 0)
{
parts.Push(m * digit);
}
}

return string.Join(" + ", parts);
}
}

이거는 표 자체는 많이 받지 못한 풀이 방식인데.

stack을 사용하여 일단 자리수를 전부 구한다음에, string join으로 " + "를 연결하는게 신박한 방식인 것 같아서 실어 봤다.

· 약 2분
karais89

Instructions

Instructions A stream of data is received and needs to be reversed.

Each segment is 8 bits long, meaning the order of these segments needs to be reversed, for example:

11111111 00000000 00001111 10101010
(byte1) (byte2) (byte3) (byte4)

should become:

10101010 00001111 00000000 11111111
(byte4) (byte3) (byte2) (byte1)

The total number of bits will always be a multiple of 8.

The data is given in an array as such:

[1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,0,1,0,1,0,1,0]

My Solution

namespace Main{

using System;
public class Kata
{
public static int[] DataReverse(int[] data)
{
const int SEG_COUNT = 8;
int segNum = data.Length / SEG_COUNT;
int[] dataRevers = new int[data.Length];
for (int i = 0; i < data.Length; i++)
{
int currSeg = i / SEG_COUNT;
int idx = ((segNum - currSeg - 1) * SEG_COUNT) + i % SEG_COUNT;
dataRevers[idx] = data[i];
}

return dataRevers;
}
}
}

8 비트씩 끊어서 뒤에다 정렬해 줘야되는 문제 for문에서 해당 인덱스값으로 변환해주어서 해결 하였다.

Best Practices

namespace Main
{

using System;
public class Kata
{
public static int[] DataReverse(int[] data)
{
int[] bits = data;

for(int i = 0; i < data.Length; i+=8)
{
Array.Reverse(bits, i, 8);
}

Array.Reverse(bits);

return bits;
}
}
}

8비트씩 끊어서 리버스를 해준다음에 전체 리버스를 해주면 해당되는 값이 나온다.

이걸 어떻게 생각했지?? 란 생각이 드네.. 기발하네..

(원래 값)
11111111 00000000 00001111 10101010
(8비트 리버스)
11111111 00000000 11110000 01010101
(전체 리버스)
10101010 00001111 00000000 11111111

· 약 2분
karais89

Instructions

You have to extract a portion of the file name as follows:

  • Assume it will start with date represented as long number
  • Followed by an underscore
  • Youll have then a filename with an extension
  • it will always have an extra extension at the end

Inputs:

1231231223123131_FILE_NAME.EXTENSION.OTHEREXTENSION

1_This_is_an_otherExample.mpg.OTHEREXTENSIONadasdassdassds34

1231231223123131_myFile.tar.gz2

Outputs:

FILE_NAME.EXTENSION

This_is_an_otherExample.mpg

myFile.tar

Acceptable characters for random tests:

abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_-0123456789

The recommend way to solve it is using RegEx and specifically groups.

My Solution

using System;

namespace Solution
{
class FileNameExtractor
{
public static bool IsOnlyNumber(string str)
{
foreach (char s in str)
{
if (s < '0' || s > '9')
{
return false;
}
}
return true;
}

public static string ExtractFileName(string dirtFileName)
{
// 앞에 숫자 제외 뒤에 확장자 제거 하고 반환?
string fileName = dirtFileName;
string[] underSplit = dirtFileName.Split('_');
string firstSplit = underSplit[0];
if (IsOnlyNumber(firstSplit))
{
// number remove
int index = fileName.IndexOf('_');
if (index != -1)
{
fileName = fileName.Substring(index + 1);
}
}

// extension remove
int exIndex = fileName.LastIndexOf('.');
if (exIndex != -1)
{
fileName = fileName.Substring(0, exIndex);
}

// Your code here
return fileName;
}
}
}

문제 자체에 아예 정규 표현식을 사용하라고 나와있다.

하지만 나는 당당히.. 정규 표현식을 사용하지 않고 풀어야지..

해결 방법은 간단하다.

  1. 언더스코어(_) 기준으로 문자열을 쪼갠다음에 맨 첫번째 문자가 숫자로 구성되어 있으면 제거 해준다.
  2. 점(.) 기준으로 또 문자열을 찾은다음에 찾은 문자열 다음에는 제거 해준다.
  3. 구한 값을 리턴 해준다.

Best Practices

using System.Text.RegularExpressions;

public class FileNameExtractor
{
public static string ExtractFileName(string s) => Regex.Match(s, @"(?<=_).+(?=\.)").Value;
}

정규 표현식을 쓰면 한줄이면 해결 할 수 있다!