문제

Python에서는 방금 텍스트 파일의 한 줄을 읽었으며 줄 시작 부분에 해시 #이 있는 주석을 무시하도록 코딩하는 방법을 알고 싶습니다.

나는 이것이 다음과 같아야 한다고 생각합니다.

for 
   if line !contain #
      then ...process line
   else end for loop 

하지만 저는 Python을 처음 접했고 구문을 모릅니다.

도움이 되었습니까?

해결책

당신이 사용할 수있는 startswith ()

예를 들어

for line in open("file"):
    li=line.strip()
    if not li.startswith("#"):
        print line.rstrip()

다른 팁

나는 당신이 다음을 볼 때 전체 줄을 무시하지 말 것을 권한다. # 성격;나머지 줄은 무시하십시오.라는 문자열 메서드 함수를 사용하면 쉽게 이 작업을 수행할 수 있습니다. partition:

with open("filename") as f:
    for line in f:
        line = line.partition('#')[0]
        line = line.rstrip()
        # ... do something with line ...

partition 튜플을 반환합니다.파티션 문자열 앞의 모든 것, 파티션 문자열, 파티션 문자열 뒤의 모든 것.따라서 인덱싱을 통해 [0] 파티션 문자열 앞부분만 가져옵니다.

편집하다:이 기능이 없는 Python 버전을 사용하는 경우 partition(), 사용할 수 있는 코드는 다음과 같습니다.

with open("filename") as f:
    for line in f:
        line = line.split('#', 1)[0]
        line = line.rstrip()
        # ... do something with line ...

이렇게 하면 문자열이 '#' 문자로 분할된 다음 분할 전의 모든 내용이 유지됩니다.그만큼 1 주장은 .split() 한 번의 분할 후 메소드 중지;왜냐하면 우리는 단지 0번째 하위 문자열을 잡고 있기 때문입니다. [0]) 당신은 같은 대답을 얻을 것입니다 1 논쟁이지만 이것이 조금 더 빠를 수도 있습니다.(@gnr의 의견 덕분에 원래 코드에서 단순화되었습니다.내 원래 코드는 정당한 이유 없이 더 지저분했습니다.고마워요, @gnr.)

자신만의 버전을 작성할 수도 있습니다. partition().여기 하나가 있습니다. part():

def part(s, s_part):
    i0 = s.find(s_part)
    i1 = i0 + len(s_part)
    return (s[:i0], s[i0:i1], s[i1:])

@dalle은 '#'이 문자열 안에 나타날 수 있다고 언급했습니다.이 사건을 제대로 처리하기가 그리 쉽지 않아서 그냥 무시했는데, 뭐라도 말했어야 했는데.

입력 파일에 인용된 문자열에 대한 충분히 간단한 규칙이 있는 경우 이는 어렵지 않습니다.합법적인 Python 인용 문자열을 허용하는 경우 어려울 것입니다. 작은 따옴표, 큰 따옴표, 줄 끝을 이스케이프하는 백슬래시가 있는 여러 줄 따옴표, 삼중 따옴표 문자열(작은 따옴표 또는 큰 따옴표 사용)이 있기 때문입니다. 심지어 원시 문자열까지!모든 것을 올바르게 처리하는 유일한 방법은 복잡한 상태 머신입니다.

그러나 단순히 인용된 문자열로 제한한다면 간단한 상태 기계로 이를 처리할 수 있습니다.문자열 내에 백슬래시로 묶인 큰따옴표를 허용할 수도 있습니다.

c_backslash = '\\'
c_dquote = '"'
c_comment = '#'


def chop_comment(line):
    # a little state machine with two state varaibles:
    in_quote = False  # whether we are in a quoted string right now
    backslash_escape = False  # true if we just saw a backslash

    for i, ch in enumerate(line):
        if not in_quote and ch == c_comment:
            # not in a quote, saw a '#', it's a comment.  Chop it and return!
            return line[:i]
        elif backslash_escape:
            # we must have just seen a backslash; reset that flag and continue
            backslash_escape = False
        elif in_quote and ch == c_backslash:
            # we are in a quote and we see a backslash; escape next char
            backslash_escape = True
        elif ch == c_dquote:
            in_quote = not in_quote

    return line

나는 "초보자"라는 태그가 붙은 질문에서 이것을 복잡하게 만들고 싶지 않았지만 이 상태 머신은 비교적 간단하므로 흥미로울 것입니다.

나는 이것에 늦었지만 쉘 스타일을 다루는 문제 (또는 파이썬 스타일) # 의견은 매우 일반적입니다.

거의 텍스트 파일을 읽을 때마다 코드를 사용하고 있습니다.
문제는 인용 또는 탈출 한 댓글을 올바르게 처리하지 않는다는 것입니다.. 그러나 그것은 간단한 경우에 효과적이며 쉽습니다.

for line in whatever:
    line = line.split('#',1)[0].strip()
    if not line:
        continue
    # process line

보다 강력한 솔루션은 사용하는 것입니다 발사:

import shlex
for line in instream:
    lex = shlex.shlex(line)
    lex.whitespace = '' # if you want to strip newlines, use '\n'
    line = ''.join(list(lex))
    if not line:
        continue
    # process decommented line

이 Shlex 접근 방식은 따옴표를 처리하고 제대로 탈출 할뿐만 아니라 많은 멋진 기능을 추가합니다 (원하는 경우 파일이 다른 파일을 소스하는 기능과 같이). 큰 파일에서 속도를 테스트하지는 않았지만 작은 물건이 충분합니다.

각 입력 라인을 필드로 분할하는 경우 (공백에서) 더 간단합니다.

import shlex
for line in instream:
    fields = shlex.split(line, comments=True)
    if not fields:
        continue
    # process list of fields 

이것은 가능한 가장 짧은 형태입니다.

for line in open(filename):
  if line.startswith('#'):
    continue
  # PROCESS LINE HERE

그만큼 startswith() 문자열의 메소드는 당신이 호출하는 문자열이 당신이 통과 한 문자열로 시작하면 true를 반환합니다.

쉘 스크립트와 같은 일부 상황에서는 괜찮지 만 두 가지 문제가 있습니다. 먼저 파일을 여는 방법을 지정하지 않습니다. 파일을 열기위한 기본 모드는 다음과 같습니다 'r', 이는 '이진 모드에서 파일 읽기'를 의미합니다. 텍스트 파일을 기대하기 때문에 'rt'. 이 차이는 UNIX와 같은 운영 체제와 관련이 없지만 Windows (및 Pre-OS X MAC)에서 중요합니다.

두 번째 문제는 열린 파일 핸들입니다. 그만큼 open() 함수는 파일 객체를 반환하며 파일을 완료 할 때 파일을 닫는 것이 좋습니다. 그렇게하려면 전화하십시오 close() 객체의 메소드. 이제 파이썬은 할 것입니다 아마 당신을 위해 이것을하십시오, 결국; 파이썬에서 객체는 참조 카운트이며, 객체의 기준 수가 0으로 들어가면 해방되고, 객체가 해제 된 후 어느 시점에서 파이썬은 파괴자를 호출합니다 (특별한 방법으로 호출됩니다. __del__). 내가 말했다 아마: Python은 프로그램이 끝나기 직전에 참조 수가 0으로 떨어지는 물체에서 실제로 소멸자를 호출하지 않는 나쁜 습관이 있습니다. 서두르고있는 것 같아요!

쉘 스크립트, 특히 파일 개체와 같은 단기 프로그램의 경우 문제가되지 않습니다. 운영 체제는 프로그램이 완료되면 열린 파일 핸들을 자동으로 정리합니다. 그러나 파일을 열고 내용을 읽고 내용을 읽은 다음 파일 핸들을 먼저 닫지 않고 긴 계산을 시작하면 Python은 계산 중에 파일 핸들을 열어 놓을 수 있습니다. 그리고 그것은 나쁜 연습입니다.

이 버전은 2.X 버전의 Python에서 작동하며 위에서 논의한 문제를 모두 해결합니다.

f = open(file, 'rt')
for line in f:
  if line.startswith('#'):
    continue
  # PROCESS LINE HERE
f.close()

이것은 이전 버전의 Python에 가장 좋은 형태입니다.

Steveha가 제안한 바와 같이, "With"진술을 사용하는 것은 이제 모범 사례로 간주됩니다. 2.6 이상을 사용하는 경우 다음과 같은 방식으로 작성해야합니다.

with open(filename, 'rt') as f:
  for line in f:
    if line.startswith('#'):
      continue
    # PROCESS LINE HERE

"with"명령문은 파일 핸들을 정리합니다.

당신의 질문에서 당신은 " #로 시작하는 줄"이라고 말했기 때문에 그것이 내가 당신에게 보여준 것입니다. 시작하는 선을 걸러 내고 싶다면 선택적 공백 그리고 그 다음에 '#', '#'를 찾기 전에 공백을 제거해야합니다. 이 경우 이것을 변경해야합니다.

    if line.startswith('#'):

이에:

    if line.lstrip().startswith('#'):

파이썬에서 문자열은 불변이므로 값을 바꾸지 않습니다. line. 그만큼 lstrip() 메소드는 모든 선행 공백이 제거 된 상태에서 문자열 사본을 반환합니다.

최근에 발전기 기능이 큰 일을한다는 것을 알았습니다. 비슷한 기능을 사용하여 주석 선, 빈 줄 등을 건너 뛰었습니다.

내 기능을 다음과 같이 정의합니다

def skip_comments(file):
    for line in file:
        if not line.strip().startswith('#'):
            yield line

그렇게하면 그냥 할 수 있습니다

f = open('testfile')
for line in skip_comments(f):
    print line

이것은 모든 코드에서 재사용 할 수 있으며 추가 처리/로깅/등을 추가 할 수 있습니다. 내가 필요하다.

나는 이것이 오래된 스레드라는 것을 알고 있지만 이것은 내 목적으로 사용하는 발전기 기능입니다. 라인에서 어디에 있는지 상관없이 댓글을 줄뿐만 아니라 선도/후행 공백 및 빈 줄을 벗겨냅니다. 다음 소스 텍스트 :

# Comment line 1
# Comment line 2

# host01  # This host commented out.
host02  # This host not commented out.
host03
  host04  # Oops! Included leading whitespace in error!

양보 :

host02
host03
host04

여기에는 데모가 포함 된 문서화 된 코드가 있습니다.

def strip_comments(item, *, token='#'):
    """Generator. Strips comments and whitespace from input lines.

    This generator strips comments, leading/trailing whitespace, and
    blank lines from its input.

    Arguments:
        item (obj):  Object to strip comments from.
        token (str, optional):  Comment delimiter.  Defaults to ``#``.

    Yields:
        str:  Next uncommented non-blank line from ``item`` with
            comments and leading/trailing whitespace stripped.

    """

    for line in item:
        s = line.split(token, 1)[0].strip()
        if s:
            yield s


if __name__ == '__main__':
    HOSTS = """# Comment line 1
    # Comment line 2

    # host01  # This host commented out.
    host02  # This host not commented out.
    host03
      host04  # Oops! Included leading whitespace in error!""".split('\n')


    hosts = strip_comments(HOSTS)
    print('\n'.join(h for h in hosts))

정상적인 사용 사례는 파일에서 주석을 제거하는 것입니다 (즉, 위의 예에서와 같이 호스트 파일). 이 경우 위의 코드의 꼬리 끝을 수정합니다.

if __name__ == '__main__':
    with open('hosts.txt', 'r') as f:
        hosts = strip_comments(f)

    for host in hosts:
        print('\'%s\'' % host)

더 컴팩트 한 버전의 필터링 표현식도 다음과 같이 보일 수 있습니다.

for line in (l for l in open(filename) if not l.startswith('#')):
    # do something with line

(l for ... ) "발전기 표현"이라고 불립니다. 여기서는 여기에서 반복되는 동안 파일에서 모든 불필요한 줄을 걸러내는 래핑 반복자 역할을합니다. 스퀘어 브레이크에서 같은 것을 혼동하지 마십시오 [l for ... ] 이는 먼저 파일의 모든 줄을 메모리로 읽은 다음 반복을 시작하는 "목록 이해력"입니다.

때때로 당신은 그것을 덜 한 줄로 읽기 쉽고 읽기 쉬운 것을 원할 수도 있습니다.

lines = open(filename)
lines = (l for l in lines if ... )
# more filters and mappings you might want
for line in lines:
    # do something with line

모든 필터는 한 번의 반복으로 즉시 실행됩니다.

Regex를 사용하십시오 re.compile("^(?:\s+)*#|(?:\s+)") 새로운 라인과 댓글을 건너 뛸 수 있습니다.

나는 사용하는 경향이있다

for line  in lines:
    if '#' not in line:
        #do something

RPARTITION을 포함하는 답변에는 # 이전의 정보를 포함 할 수 있으므로 내 Upvote가 있습니다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top