반응형

리눅스 계열 OS에서 많이 사용되는 쉘스크립트의 형식(인덴트:indent 와 같은 줄맞춤?)을 자동으로 해주는 파이썬 라이브러리가 있어 스크랩한다.


쉘스크립트 경우 대부분 작성을 vim이나 notepad같은 별도의 IDE를 사용하지 않기때문에 여타  IDE처럼 인덴트를 자동으로 잡아주는 기능이 없다.


파이썬 파일로 아래 내용을 저장후 해당파일을 실행해주면 된다.


공식사이트는 https://arachnoid.com/python/beautify_bash_program.html 이며 라이센스는 GNU General Public License.



실행명령:

python beautify_bash.py file1.sh


파일:

beautify_bash.py


소스코드:

 
#!/usr/bin/env python
# -*- coding: utf-8 -*-

#**************************************************************************
#   Copyright (C) 2011, Paul Lutus                                        *
#                                                                         *
#   This program is free software; you can redistribute it and/or modify  *
#   it under the terms of the GNU General Public License as published by  *
#   the Free Software Foundation; either version 2 of the License, or     *
#   (at your option) any later version.                                   *
#                                                                         *
#   This program is distributed in the hope that it will be useful,       *
#   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
#   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
#   GNU General Public License for more details.                          *
#                                                                         *
#   You should have received a copy of the GNU General Public License     *
#   along with this program; if not, write to the                         *
#   Free Software Foundation, Inc.,                                       *
#   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
#**************************************************************************

import re, sys

PVERSION = '1.0'

class BeautifyBash:

  def __init__(self):
    self.tab_str = ' '
    self.tab_size = 2

  def read_file(self,fp):
    with open(fp) as f:
      return f.read()

  def write_file(self,fp,data):
    with open(fp,'w') as f:
      f.write(data)

  def beautify_string(self,data,path = ''):
    tab = 0
    case_stack = []
    in_here_doc = False
    defer_ext_quote = False
    in_ext_quote = False
    ext_quote_string = ''
    here_string = ''
    output = []
    line = 1
    for record in re.split('\n',data):
      record = record.rstrip()
      stripped_record = record.strip()
      
      # collapse multiple quotes between ' ... '
      test_record = re.sub(r'\'.*?\'','',stripped_record)
      # collapse multiple quotes between " ... "
      test_record = re.sub(r'".*?"','',test_record)
      # collapse multiple quotes between ` ... `
      test_record = re.sub(r'`.*?`','',test_record)
      # collapse multiple quotes between \` ... ' (weird case)
      test_record = re.sub(r'\\`.*?\'','',test_record)
      # strip out any escaped single characters
      test_record = re.sub(r'\\.','',test_record)
      # remove '#' comments
      test_record = re.sub(r'(\A|\s)(#.*)','',test_record,1)
      if(not in_here_doc):
        if(re.search('<<-?',test_record)):
          here_string = re.sub('.*<<-?\s*[\'|"]?([_|\w]+)[\'|"]?.*','\\1',stripped_record,1)
          in_here_doc = (len(here_string) > 0)
      if(in_here_doc): # pass on with no changes
        output.append(record)
        # now test for here-doc termination string
        if(re.search(here_string,test_record) and not re.search('<<',test_record)):
          in_here_doc = False
      else: # not in here doc
        if(in_ext_quote):
          if(re.search(ext_quote_string,test_record)):
            # provide line after quotes
            test_record = re.sub('.*%s(.*)' % ext_quote_string,'\\1',test_record,1)
            in_ext_quote = False
        else: # not in ext quote
          if(re.search(r'(\A|\s)(\'|")',test_record)):
            # apply only after this line has been processed
            defer_ext_quote = True
            ext_quote_string = re.sub('.*([\'"]).*','\\1',test_record,1)
            # provide line before quote
            test_record = re.sub('(.*)%s.*' % ext_quote_string,'\\1',test_record,1)
        if(in_ext_quote):
          # pass on unchanged
          output.append(record)
        else: # not in ext quote
          inc = len(re.findall('(\s|\A|;)(case|then|do)(;|\Z|\s)',test_record))
          inc += len(re.findall('(\{|\(|\[)',test_record))
          outc = len(re.findall('(\s|\A|;)(esac|fi|done|elif)(;|\)|\||\Z|\s)',test_record))
          outc += len(re.findall('(\}|\)|\])',test_record))
          if(re.search(r'\besac\b',test_record)):
            if(len(case_stack) == 0):
              sys.stderr.write(
                'File %s: error: "esac" before "case" in line %d.\n' % (path,line)
              )
            else:
              outc += case_stack.pop()
          # sepcial handling for bad syntax within case ... esac
          if(len(case_stack) > 0):
            if(re.search('\A[^(]*\)',test_record)):
              # avoid overcount
              outc -= 2
              case_stack[-1] += 1
            if(re.search(';;',test_record)):
              outc += 1
              case_stack[-1] -= 1
          # an ad-hoc solution for the "else" keyword
          else_case = (0,-1)[re.search('^(else)',test_record) != None]
          net = inc - outc
          tab += min(net,0)
          extab = tab + else_case
          extab = max(0,extab)
          output.append((self.tab_str * self.tab_size * extab) + stripped_record)
          tab += max(net,0)
        if(defer_ext_quote):
          in_ext_quote = True
          defer_ext_quote = False
        if(re.search(r'\bcase\b',test_record)):
          case_stack.append(0)
      line += 1
    error = (tab != 0)
    if(error):
      sys.stderr.write('File %s: error: indent/outdent mismatch: %d.\n' % (path,tab))
    return '\n'.join(output), error

  def beautify_file(self,path):
    error = False
    if(path == '-'):
      data = sys.stdin.read()
      result,error = self.beautify_string(data,'(stdin)')
      sys.stdout.write(result)
    else: # named file
      data = self.read_file(path)
      result,error = self.beautify_string(data,path)
      if(data != result):
        # make a backup copy
        self.write_file(path + '~',data)
        self.write_file(path,result)
    return error

  def main(self):
    error = False
    sys.argv.pop(0)
    if(len(sys.argv) < 1):
      sys.stderr.write('usage: shell script filenames or \"-\" for stdin.\n')
    else:
      for path in sys.argv:
        error |= self.beautify_file(path)
    sys.exit((0,1)[error])

# if not called as a module
if(__name__ == '__main__'):
  BeautifyBash().main()


반응형

휘발유를 영어로 쓰면 가솔린(Gasoline)이며, 경유는 디젤(Diesel)이다.


처음 차량 운전을 시작하는 초보운전자이거나, 첫차를 운전하는 사람들은


주유소에 들어가면 혼동하기 쉬운 용어이다.


쉽게 숙지하기 위해 아래 내용을 참고바란다.



휘.발.유.  =  가.솔.린.

둘다 3글자

경.유.  =  디.젤.

둘다 2글자


휘발유와 가솔린, 경유와 디젤 모두 글자수가 각각 같기 때문에


위처럼 숙지하는것이 쉽고 편하다.


반응형



카카오 미니 AI스피커와 멜론을 이용하고 있다가


이번에 이용권이 좀 더 저렴한 모바일 스트리밍으로 변경했다가


카카오 미니 스피커에서 멜론 이용이 안되서 확인해 보니


카카오 스피커를 이용하려면 모바일 전용이 아닌 이용권으로 변경해야한다.


- 사용 가능: 스트리밍 플러스, 스트리밍 클럽, MP3 30 플러스, MP3 50 플러스, MP3 100 플러스, 프리클럽, Hi-Fi 스트리밍 클럽, 100회 듣기, 300회 듣기, 500회 듣기, 멜론 익스트리밍 플러스


- 사용 불가능: 모바일 스트리밍 클럽, MP3 30, MP3 50, MP3 70, 어학 프리클럽, 어학 스트리밍 클럽, 멜론 익스트리밍, 멜론 프리티켓 공동 프로모션

아래는 고객센터 FAQ 관련 글 캡쳐.





반응형

Official Download : https://gameguardian.net/download



Mirror:

GameGuardian.75.0.zip

GameGuardian.75.0.z01


Nox:

GameGuardian.75.0_for_Nox.zip

GameGuardian.75.0_for_Nox.z01


Screenshot



012345678910


반응형

STL에 포함되어 있는 다양한 컨테이너(Vector, Map, List etc...)들은 Iterator를 기본 제공한다.


Iterator를 쉽게 설명하자면 컨테이너의 각각의 Index를 탐색 or 순환 할 수 있는 일종의 포인터 개념이다.


STL의 컨테이너에 Iterator를 붙여서 사용하면 일반 배열 탐색할때 인덱스를 반복문으로 훓으면서 쓰던것처럼 할 수 있다.


근데 문제는 이 Iterator를 쓰기 좀 번거롭다.


for (std::map<std::string, bool>::iterator iter = m_mapItemFlag.begin(); iter != m_mapItemFlag.end(); iter++)
{
	(*iter).second = bCheckFlag;
}

위의 코드처럼 Map이든 Vector든 내부의 각 원소를 전부 탐색해서 원소를 초기화 하거나 조건식을 추가하여 조건에 맞는 원소들의 값을 이용하는 것으로 많이 사용한다.



기존의 배열을 반복문과 함께 이용하는 것과 매우 흡사하다.



위처럼 Iterator를 컨테이너의 처음부터 끝까지 탐색할 경우 아래와 같은 방법으로 하면 쉽게 해결된다.


for (auto item : m_mapItemFlag)
{
	item.second = bCheckFlag;
}

C#보다 C++에 익숙한 사람은 auto 키워드에 낯설수도 있다. 나도 그랬다.


C#의 var 키워드 처럼 뒤에 대입받는 자료형에 따라 자동으로 해당 변수의 자료형을 선택해주는 아주 편한 키워드이다. 


하지만 남용하면 가독성이 떨어지므로 위와 같이 Range-based. 범위기반 반복문에서나 사용하자.



요약하자면 STL 컨테이너든, 일반 배열이든, 전체를 순차적으로 탐색할 때에는 위와 같은 범위기반 반복문을 사용하면 훨씬 편하다는 거다.


복잡하게 Iterator 생성해서 형식 맞춰주고 할 필요가 없다. 





반응형

지난번에 C++를 이용하여 로또(6/45) 번호를 생성하는 코드를 작성해봤는데 이번에는 C#을 이용하여 작성해봤다.


2019/03/29 - [Programming] - [C++] 로또 번호 생성 코드 (rand, list)



코드는 여타 로또 번호 생성하는 코드와 비슷하게 Rand함수를 이용한다.


C++ 이든 C#이든 Rand함수를 이용할 때 시드값(Seed)을 넣어줘야만 난수 생성시 중복되는 경우를 줄일 수 있다.


코드는 아래와 같다.


        private List GetLotteryNumber()
        {
            int nNum = 0;
            List listLottery = new List();
            for (int i = 0; i < LOTTONUM; i++)
            {
                Random rand = new Random(((int)DateTime.Now.Ticks) + i);
                nNum = rand.Next(1, 45);
 
                if(!listLottery.Contains(nNum))
                    listLottery.Add(nNum);
                else{
                    i--;
                    continue;
                }
            }
            return listLottery;
        } 


GetLotteryNumber 함수의 리턴값 타입으로 List를 이용했는데 이건 내가 쓰기 편해서 List를 이용했다.

더 쉬운 방법으로 배열을 이용하면 된다.

Random함수를 통해 난수를 1부터 45까지의 난수를 생성하여 중복된 값인지 체크하고 중복값이라면 반복문을 한스텝 빼주고 continue로 처리했다.


+ Recent posts