태그 보관물: python

[Python] Read excel(xlsx)

xlrd 를 이용한 엑셀 파일 읽기


기능

xlsx 파일에서 cell에 입력된 Text 데이터를 모두 출력한다. 출력 포맷은 excel 데이터와 동일하게 출력하도록 한다. (ROW별로 출력)

리소스정보

  • 입력: 컨텐츠가 포함된 xlsx 파일(resource.xlsx)

소스코드
#-*- coding: utf-8 -*-
# ================================================
# Author: coozplz@gmail.com
# Date: 2015. 08. 11
# Desc: 토플 앱 개발에 필요한 엑셀 파일 분석
# ================================================

import xlrd

def open_excel(path):
    '''
    엑셀 파일에 포함된 내용을 system.out으로 출력한다. 
    '''
    workbook = xlrd.open_workbook(path)

    # 엑셀 시트 개수 정보 출력
    print workbook.nsheets
    # 0번 시트정보를 조회한다.
    sheet = workbook.sheet_by_index(0)
    for row_num in range(sheet.nrows):
        row = sheet.row(row_num)
        cols = []
        for cell in row:
            if (cell.ctype == 1):
                cols.append(cell.value)
        print ','.join(cols)

#
# Main
#
if __name__ == '__main__':
    path = './word_end_0811.xlsx'
    open_excel(path)

[ST3] Python 개발환경 설정하기

Sublime Text 3(ST3) Python 개발환경 설정하기

맥에서 사용하는 Sublime Text 3 를 파이썬 개발 환경으로 사용하기 위한 설정에 대해 정리

ST3 다운로드 및 인스톨

다운로드

패키지 인스톨러 설치

다운로드

링크 생성

$ sudo ln -s /Applications/Sublime\ Text.app/Contents/SharedSupport/bin/subl /usr/bin/subl

테마 다운로드

인스톨 패키지를 이용하여 설치.

  • Flatland

환경설정

사용자 설정

경로: Preferences > Settings – User

{
  "auto_complete": false,
  "auto_complete_commit_on_tab": true,
  "auto_match_enabled": true,
  "bold_folder_labels": true,
  "caret_style": "solid",
  "color_scheme": "Packages/Theme - Flatland/Flatland Dark.tmTheme",
  "detect_indentation": true,
  "draw_indent_guides": true,
  "ensure_newline_at_eof_on_save": true,
  "file_exclude_patterns": [
    "*.DS_Store",
    "*.pyc",
    "*.git"
  ],
  "find_selected_text": true,
  "fold_buttons": false,
  "folder_exclude_patterns": [],
  "font_face": "Menlo",
  "font_options": [
    "no_round"
  ],
  "font_size": 13,
  "highlight_line": true,
  "highlight_modified_tabs": true,
  "ignored_packages": [
    "Vintage"
  ],
  "indent_to_bracket": true,
  "line_padding_bottom": 0,
  "line_padding_top": 0,
  "match_brackets": true,
  "match_brackets_angle": false,
  "match_brackets_braces": true,
  "match_brackets_content": true,
  "match_brackets_square": true,
  "new_window_settings": {
    "hide_open_files": true,
    "show_tabs": true,
    "side_bar_visible": true,
    "status_bar_visible": true
  },
  "remember_open_files": true,
  "remember_open_folders": true,
  "save_on_focus_lost": true,
  "scroll_past_end": false,
  "show_full_path": true,
  "show_minimap": false,
  "tab_size": 2,
  "theme": "Flatland Dark.sublime-theme",
  "translate_tabs_to_spaces": true,
  "trim_trailing_white_space_on_save": true,
  "use_simple_full_screen": true,
  "vintage_start_in_command_mode": false,
  "wide_caret": true,
  "word_wrap": true
}

Python 환경 설정

  • 경로: Preferences > Settings – User 설정 파일 위치와 동일한 위치
  • 파일명: Python.sublime-settings
 
{
 "draw_white_space": "all",
 "auto_indent": true,
 "rulers": [
 79
 ],
 "smart_indent": true,
 "tab_size": 4,
 "trim_automatic_white_space": true,
 "use_tab_stops": true,
 "word_wrap": true,
 "wrap_width": 80
}

플러그인 설치

SideBarEnhancements
Anacoda
  • Lint 제거Preferences > Package Setting > Anaconda > User – Setting {“anaconda_lint” : false}
  • 단축키
    • Goto Definition: ctrl + alt + g
    • Find Usages : ctrl + alt + f
    • Get Documentation: ctrl + alt + d
SublimeLinter-pep8 and SublimeLinter-pyflakes
GitGutter
SublimeREPL
  1. 단축키 생성 방법
    1. SublimeREPL.sublime-build 파일 생성
      경로: ~/Application Support/Sublime Text 3/Packages/User
    2. SublimeREPL.sublime-build 설정 내용 추가
    3. {
          "target": "run_existing_window_command", 
          "id": "repl_python_run",
          "file": "config/Python/Main.sublime-menu"
      }
      
    4. command + b 빌드 결과 출력 여부 확인
  • 단축키
    • Goto Definition: ctrl + alt + g
    • Find Usages : ctrl + alt + f
    • Get Documentation: ctrl + alt + d
 

참조링크

[Python] 폴더내 파일명 일괄 변경

폴더내 파일명 일괄 변경


개발내용

플래시 컨텐츠 테스트를 위해 폴더내 파일명을 특정 패턴에 맞게 일괄로 변경해야 되는 이슈가 있어 개발.

개발환경

  • Language: Python 2.7.10
  • OS: Windows 7 64bit

소스코드
#-*- coding: utf-8 -*-
# ===============================================================
# Author: coozplz@gmail.com
# File: flash_korean_file_rename.py
# Date: 2015. 07. 14
# Desc: 플래시 샘플 컨텐츠들의 이름을 변경하기 위한 프로그램.
# ===============================================================

import os

def rename_flash_content(path, key, startIndex):
	'''
	플래시 샘플 컨테츠의 이름을 변경한다.
	:param path 루트 디렉토리 경로
	:param key 컨텐츠 구분값(명사: N, 형용사: A, 동사: V, 인사말:G)
	:param startIndex 컨텐츠 시작 번호
	'''
	print 'path=%s' % path
	minValue = i = startIndex;
	j = 1

	for item in os.listdir(root):
		# 파일명과 확장자를 분리한다.
		# item: 493-A023-c.swf
		# filename: 493-A023-c
		# file_extension: .swf
		filename, file_extension = os.path.splitext(item)

		if (file_extension != '.swf'):
			print 'invalid file name %s' % item
			continue;

		# item의 절대 경로를 구한다.
		fullpath = os.path.join(root, item)

		mod = j % 4
		suffix = 'a'
		if mod == 1:
		suffix = 'b'
		elif mod == 2:
		suffix = 'c'
		elif mod == 3:
		suffix = 'd'
		else:
		suffix = 'a'

		# 변경할 이름의 포맷을 정의한다.
		renamed_file_name = "%d-%s%03d_%s.swf" % (i, key, i - minValue + 1, suffix)
		if (key == 'NUM'):
			renamed_file_name = "%d-%s%02d_%s.swf" % (i, key, i - minValue + 1, suffix)
		#endif	
		if (j % 4 == 0):
			i = i+1
			j=j+1
			rename_full_path = os.path.join(root, renamed_file_name)
			os.rename(fullpath, rename_full_path)
			print '%s is rename to %s' % (item, renamed_file_name)
		#end - if
	#end - for	
if __name__ == '__main__':
	root = "D:/git/flash_korean_novice/resources/ai/verb"
	key = 'V'
	startIndex=321
	print root
	rename_flash_content(root, key, startIndex)
#end-if	

[Python] AndroidLint result to CSV

최근 개발 도구를 JetBrain 라인의 제품을 사용하고 있습니다.

Android는 AndroidStudio를 이용해서 하고 Java는 IntelliJ를 이용하고 Python은 PyCharm을 이용해서 하고 있습니다.

같은 회사의 제품을 사용하니 단축키를 동일하게 할 수 있어 좋습니다.
물론 Android Studio에서 Eclipse 단축키를 제공하기는 하지만 저는 그냥 단축키를 바꾸는 편을 선호 합니다.

예전에 PC방에 가도 단축키를 모두 바꿔서 적응하면 게임방을 옮길때마다 변경해줘야 하는 불편함이 있어서 몸에 벤 방식이 기본을 그대로 사용하고 있습니다. (많이 불편하면 변경을 합니다.)

잡설은 빼고… 어쨌든 정적 분석도구를 이용해서 분석한 후 Export를 하려고 하니 HTML, XML 두가지 방식을 지원합니다. XML로 저장 후 Excel로 읽을려고 하니 안될꺼 같아. 내용만 뽑아 CSV형태로 저장하는 방식으로 했습니다.

[Problem]
AndroidStudio에서 Lint를 이용해 분석된 XML 결과를 Excel로 보고싶다.

[Solution]
XML을 파싱해서 분석 후 CSV 형태로 저장하자.

[Review]
너무 간단하게 파싱이 되서 당황했습니다. 지금은 Java로 작성하는게 훨씬 편한거 같은데 python이 익숙해지면 훨씬 쉽게 작성할 수 있을 것 같습니다.
그리고 Linux에서는 python을 기본으로 제공해주니 별도의 설치도 필요 없습니다.(Python3는 별도로 설치해야함)

"""
# AndroidLintParser.py
# Author: coozplz@gmail.com
# Date: 2014. 08. 06
# Desc: Parse android stuidio's code analyze result(xml) to csv.
# usage: AndroidLintParser.py [-h] input output
    positional arguments:
      input       Android lint export path
      output      Output csv path
# Input:
<problems>
    <problem>
        <file>....</file>
        <line>9</line>
        <module>...</module>
        <package>...</package>
        <entry_point TYPE="field" FQNAME="..." />
        <problem_class severity="WARNING" attribute_key="WARNING_ATTRIBUTES">
                                    Declaration can have final modifier
        </problem_class>
        <hints />
        <description>Declaration can have final modifier</description>
  </problem>
</problems>
# Output:
=============================================================
    SEVERITY, MODULE, PACKAGE, FILE_NAME, LINE, DESC
=============================================================
"""
from xml.etree.ElementTree import parse
from xml.sax.saxutils import unescape
from os import listdir
from os import path
import argparse
import sys
'''
# 입력 파라미터를 설정한다.
'''
parser = argparse.ArgumentParser()
parser.add_argument("input", help="Android lint export path", type=str)
parser.add_argument("output", help="Output csv path", type=str)
args = parser.parse_args()

# 사용자가 input path의 마지막에 '/' 를 붙이지 않을 수도 있기 임의로 붙여준다.
# 두개를 붙여도 상관은 없다
XML_INPUT = args.input+"/"
CSV_OUTPUT = args.output


def parse_android_lint_to_csv(element):
    """
    AndroidLint 의 Problem Tag 를 분석하여 원하는 값을 추출한다.
    :param element: Problem Element
    :return: output String
    """
    filename = element.findtext("file")
    filename = filename[filename.rfind("/")+1:]
    entry_point = element.find("entry_point").get("FQNAME")
    entry_point = entry_point.split(' ')
    if len(entry_point) > 1:
        entry_point = entry_point[1]
    line = element.findtext("line")
    module = element.findtext("module")
    package = element.findtext("package")
    severity = element.find("problem_class").get("severity")
    desc = unescape(element.findtext("description"))
    if severity == "TYPO" or severity is "None":
        return
    return "{0},{1},{2},{3},{4},{5},{6}\n".format(severity,
                                                  module,
                                                  package,
                                                  filename,
                                                  entry_point,
                                                  line,
                                                  desc)


'''
#Main
'''
try:

    f = open(CSV_OUTPUT, "w")
except IOError:
    print('cannot open', CSV_OUTPUT)
else:
    try:
        # 제외 파일명 저장용 배열
        exceptFiles = []
        # 제외된 파일의 개수
        exceptFileCount = 0
        # 총 파일의 개수
        count = 0
        for iterFileName in listdir(XML_INPUT):
            count += 1
            if iterFileName.lower().find(".xml") < 0:
                '''
                # 파일명이 Xml 형식이 아닌것은 제외 목록에 추가하고 처리하지 않는다.
                '''
                exceptFileCount += 1
                exceptFiles.append(iterFileName)
                continue
            xmlDoc = parse(XML_INPUT + iterFileName)
            problems = xmlDoc.getroot()
            for parent in problems:
                data = parse_android_lint_to_csv(parent)
                if data:
                    # 데이터가 있는 경우에만 파일에 쓴다
                    f.write(data)
    except IOError as ioE:
        print("I/O error: {0}".format(ioE))
    except ValueError as ve:
        print("Could not convert data: {0}".format(ve))
    except:
        print("UnExpected error", sys.exc_info()[0])
        raise
finally:
    # 파일은 반드시 닫는다
    f.close()


# 결과를 출력
print("TOTAL={0}".format(count))
print("OUTPUT_FILE_NAME={0}".format(CSV_OUTPUT))
print("OUTPUT_FILE_SIZE=%0.2f KBytes" % (path.getsize(CSV_OUTPUT) / 1024))
if exceptFileCount > 0:
    print("EXCEPT={0}, EXCEPT_FILES={1}".format(exceptFileCount,
                                                exceptFiles))

[Python] 5-SmallestMultiple

알고리즘은 생각하지 않고 하루에 한 문제씩 풀면서 파이썬이란 언어와 친해지려고 합니다..
혹시 보시고 잘못된 부분이나 지적하실 부분이 있으면 댓글로 남겨주세요..

[문제 링크]
http://projecteuler.net/problem=5

[문제 요약]
1에서 20으로 모두 나눠지는 가장 작은 수를 구하시오..

[풀이 리뷰]
알고보면 간단한 문젠데 이해가 안되서 고민을 좀 했습니다.
프로젝트오일러에 나온 문제들은 대부분 1분내외로 풀어야 한다고 합니다.
제가 풀려고 했던 방법은 2의 배수중 20 보다 작은 가장 큰 수, 3의 배수중 20보다 작은 가장 큰수…. + 20이하의 모든 소수로 나눠지는 수를 계산하려고 했습니다.

나름 머리를 쓴다고 쓴게 반복을 최소화해서 속도를 높여보자였는데 간단한 방법이 있었습니다.

최소공배수(Least Common Multiple)를 이용하는 방법입니다.

lcm(lcm(lcm(lcm(1,2),3),4)…., 20)
위와 같은 방법으로 하면 연산을 많이 하지 않고도 답을 구할 수 있습니다.

[소스 코드]

"""
# 5_SmallestMultipl.py
# Date: 2014. 08. 04
# Author: coozplz@gmail.com
"""
import time

sTime = time.clock()
def gcd(a,b):
   """
   최대 공약수를 구하는 함수
   :param a: 숫자 입력값 1
   :param b: 숫자 입력값 2
   :return:최대 공약수
   """
   m = max(a,b)
   n = min(a,b)
   while n != 0:
       t = m % n
       (m,n)=(n,t)
   return abs(m)


"""
# 1. 숫자 1과 숫자 2의 최소공배수를 구한다.
# 2. 1의 결과와 3의 최소공배수를 구한다.
# ....
# 이전의 결과와 20의 최소공배수를 구한다.
"""

gcdValue = 1
for j in range(1, 21):
    # 최소 공배수를 구한다
    gcdValue = int(gcdValue * j / gcd(gcdValue, j))
    i = j
print(gcdValue, "최소공배수 이용=", (time.clock() - sTime) * 100)

"""
# 단순 무식하게 반복문으로 1씩 증가하면서 모두 해본다.
"""
sTime = time.clock()
num = 1
while True:
    found = True
    for i in range(1, 21):
        if num % i != 0:
            found = False
            break
    if found:
        break
    num += 1
print(num, "반복문만 사용=", (time.clock() - sTime) * 100)

[풀이 시간]
최소공배수 이용= 0.0030000000000000512
반복문만 사용= 14033.343700000001

[Python] 22 – Name Scores

[문제 링크]
http://projecteuler.net/problem=22

[문제 요약]
“names.txt” 정렬이 안된 텍스트 파일을 읽어 모든 이름을 아래의 룰에 따라 연산한 합의 결과를 출력
COLIN 은 알파벳 순서로 정렬시 938번째에 존재한다.
C = 3
O = 15
L = 12
I = 9
N = 14
========
SUM = 53

nameScore = 938 * 53 = 49714

그렇다면 텍스트 파일에 포함된 모든 숫자의 nameScore의 합은?

[문제 풀이]
1. 파일을 읽는다.
2. 파일을 쉼표(,) 를 기준으로 split() 한다.
3. split() 된 파일을 정렬한다.
4. split() 의 결과를 반복하며 알파벳의 순서를 합산한다.

[소스코드]

"""
# 22_Names_scores.py
# Date: 2014. 08. 01
# Author: coozplz@gmail.com
# 학습내용
    1. 파일 읽기
    2. 리스트 정렬
    3. Character 를 ASCII 코드값으로 출력
"""

#이름 정보를 저장할 파일명
nameList = []

f = open("names.txt", "r")
# 파일을 읽는다.
line = f.read()

# 라인을 , 를 구분으로 자른다.
aStr = line.split(",")

for n in aStr:
    nameList.append(n)

print("Size =", len(nameList))

#이름을 정렬한다.
nameList.sort()

# 합산 점수를 저장
sumOfScores = 0

# 이름의 위치한 행의 번호
rowCount = 1


for name in nameList:
    nameCount = 0
    '''
    # 이름에 따옴표가 포함된 경우 제거
    '''
    name = name.replace("\"", "")
    for ch in name:
        '''
        # 이름을 한자씩 잘라서 ASCII 값으로 알파벳의 덧셈을 처리한다.
        # Ex) A = 1, B = 2
        '''
        nameCount += (ord(ch) - (ord('A')-1))

    sumOfScores += (nameCount * rowCount)
    rowCount += 1
print(sumOfScores)

[Python] 21 – Amicable Numbers

[문제 링크]
http://projecteuler.net/problem=21

[문제 원본]
Let d(n) be defined as the sum of proper divisors of n (numbers less than n which divide evenly into n).
If d(a) = b and d(b) = a, where a ≠ b, then a and b are an amicable pair and each of a and b are called amicable numbers.

For example, the proper divisors of 220 are 1, 2, 4, 5, 10, 11, 20, 22, 44, 55 and 110; therefore d(220) = 284. The proper divisors of 284 are 1, 2, 4, 71 and 142; so d(284) = 220.

Evaluate the sum of all the amicable numbers under 10000.

[문제 풀이]

  • 반복문에서 수를 감소시키며 숫자의 약수의 합을 구한다.
  • 1에서 구해진 약수의 합의 수의 약수의 합을 구한다.
  • 2에서 구해진 값과 진행 중인 숫자가 일치하면 Amicable Number로 인식한다.단, 1에서 구해진 약수의 합과 진행 중인 숫자가 같은 경우는 제외한다.

[소스 코드]

"""
# 19_Amicable_Numbers.py
# Date: 2014. 07. 31
# Author: coozplz@gmail.com
"""
num = 10000
sumOfAmicable = 0

while(num > 0) :
    sumOfDivisor = 0
    for i in range(1, num):
        if(num % i == 0):
            # 약수의 합을 구한다.
            sumOfDivisor = sumOfDivisor + i

    sumOfDivisor2 = 0
    for i in range(1, sumOfDivisor):
        if(sumOfDivisor % i == 0):
            # 약수의 합을 구한다.
            sumOfDivisor2 = sumOfDivisor2 + i


    """
    # 약수의 합과 수가 일치하지만 두수가 동일한 경우는 제외한다.
    # 예) 28 // 28
    #      6 // 6
    """
    if(sumOfDivisor2 == num and num != sumOfDivisor) :
        print("AmicableNumber=", num, sumOfDivisor)
        sumOfAmicable = sumOfAmicable + num
    num = num - 1
print(sumOfAmicable)

[Python] 19 – Counting Sundays

문제 이해를 잘못해서 시간이 엄청 걸렸습니다.

제출을 하면 어디가 잘못되었는지가 나오지 않기 때문에 문제를 정확하게 파악해야 됩니다.

이번에 실수는 1901~2000까지 일요일의 수를 카운팅 하는건줄 알았는데 알고보니 월의 처음 시작일이 일요일인 것만 찾는 문제였습니다.

소스코드에 불필요한 부분이 많이 있더라도 파이썬에 익숙해보고자 하는 일이기 때문에 … 이해 부탁드립니다.

[문제 링크]
http://projecteuler.net/problem=19

[문제 원본]
You are given the following information, but you may prefer to do some research for yourself.

1 Jan 1900 was a Monday.
Thirty days has September,
April, June and November.
All the rest have thirty-one,
Saving February alone,
Which has twenty-eight, rain or shine.
And on leap years, twenty-nine.
A leap year occurs on any year evenly divisible by 4, but not on a century unless it is divisible by 400.
How many Sundays fell on the first of the month during the twentieth century (1 Jan 1901 to 31 Dec 2000)?

[풀이 방법]
1. 1900~1901년까지 월의 시작요일이 일요일인 개수를 구한다.
2. 1900~2000년까지 월의 시작요일이 일요일인 개수를 구한다.
3. 2의 결과에서 1의 결과를 제거한다.

위와 같이 한 이유는 문제에서 주어진 처음 시작 요일이 1900년 1월 1일 이기 때문입니다.
[소스 코드]

#
#19_Counting_Sundays.py
#
months = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]
days = ["MON", "TUE", "WED", "THU", "FRI", "SAT", "SUN"]

'''
#### 함수 정의 부분 ####
'''
def countingSundays(sYear, eYear):
    """ 주어진 기간 동안에 월의 시작요일이 일요일인 항목은 구한다.
    :param sYear: 시작 월
    :param eYear: 마지막 월
    :return:       월의 시작 요일이 일요일인 개수
    """

    count = 0
    sumOfDays = 0

    while(sYear <= eYear) :
        if((sYear % 4 == 0 and sYear%100 != 0) or (sYear % 400 == 0)) :
            months[1] = 29
        else :
            months[1] = 28
        for i in months :
            if(days[sumOfDays % 7] == 'SUN'):
                count = count+1
            sumOfDays = sumOfDays + i
        sYear = sYear + 1

    return count

'''
#### 메인 실행 부분 ####
'''
sumUtil1901 = countingSundays(1900, 1900)
print("Sundays fell on the first of the month until 1901 =", sumUtil1901)
print("Sundays fell on the first of the month = ", countingSundays(1900, 2000) - sumUtil1901)

[Python] 20 – Factorial digit sum

[문제 링크]
http://projecteuler.net/problem=20

[문제 원본]
n! means n × (n − 1) × … × 3 × 2 × 1

For example, 10! = 10 × 9 × … × 3 × 2 × 1 = 3628800,
and the sum of the digits in the number 10! is 3 + 6 + 2 + 8 + 8 + 0 + 0 = 27.

Find the sum of the digits in the number 100!

[풀이방법]
1. 반복문을 통해 팩토리얼의 값을 구한다.
2. 팩토리얼 값을 String 타입으로 변경한다.
3. 변경된 String 값을 한자씩 추출하여 Integer 타입으로 변경한다.
4. 변경된 Integer 타입을 더한다.

[소스코드]

#20_FactorialDigitSum.py

num = 100
sum = 1
while(num > 0) :
	sum = sum * num
	num = num -1

strNum = str(sum)
num = 0
for i in range(0, len(strNum)):
	#print(strNum[i], end=' ')
	num = num  + int(strNum[i])

print("DigitSum=", num)

[Python] 16 – Power digit sum

[문제 링크]
http://projecteuler.net/problem=16
[문제 원본]
2^15 = 32768 and the sum of its digits is 3 + 2 + 7 + 6 + 8 = 26.

What is the sum of the digits of the number 2^1000?

[소스 코드]

#python PowerDigitSum.py

input = input("number = ")
count = 1000
sum = 1;
for i in range(1, count+1):
    sum = sum * int(input)
str = str(sum)
print("Sum=", sum)

digitSum = 0
for j in range(0, len(str)):
    # print(str[j])
    digitSum = digitSum + int(str[j])
print("Digitsum=", digitSum)
print("Done")

[결과]
number = 2
Sum= 107150860718626732094842504906000181056140481170553360744375038837035105112
49361224931983788156958581275946729175531468251871452856923140435984577574698574
80393456777482423098542107460506237114187795418215304647498358194126739876755916
5543946077062914571196477686542167660429831652624386837205668069376
Digitsum= 1366
Done