2011-03-09 5 views
6

루아의 문자열에서 N 위치의 문자를 대체 할 방법이 있습니까? 루아에서 문자열의 문자 수정하기

내가 지금까지 가지고 올 한 것입니다 :

function replace_char(pos, str, r) 
    return str:sub(pos, pos - 1) .. r .. str:sub(pos + 1, str:len()) 
end 

str = replace_char(2, "aaaaaa", "X") 
print(str) 

내가 GSUB 사용할 수 있습니다 그 위치 N.에서 모든 캡처뿐만 아니라 캡처를 교체하는 것처럼

답변

12

루아의 문자열은 변경 불가능합니다. 즉, 문자열의 텍스트를 대체하는 솔루션은 결국 원하는 내용으로 새 문자열을 구성해야합니다. 단일 문자를 다른 내용으로 바꾸는 특별한 경우에는 원래 문자열을 접두사 부분과 접미사 부분으로 분할하고 새 내용을 중심으로 다시 연결해야합니다.

코드에이 변화 :

function replace_char(pos, str, r) 
    return str:sub(1, pos-1) .. r .. str:sub(pos+1) 
end 

루아를 간단하게 할 수있는 가장 직접적인 번역이다. 아마도 대부분의 경우 충분히 빠릅니다. 접두어가 첫 번째 pos-1 문자 여야한다는 버그를 수정했으며 string.sub의 마지막 인수가 누락 된 경우 해당 문자열의 끝에 해당하는 -1으로 간주된다는 사실을 이용했습니다.

가비지 콜렉션이 문자열을 저장할 때까지 문자열 저장소에 임시 문자열이 여러 개 생성된다는 점에 유의하십시오. 접두어와 접미사의 임시 변수는 어떤 솔루션에서도 피할 수 없습니다. 그러나 이것은 또한 첫 번째 .. 연산자가 임시로 소비해야합니다.

두 가지 대체 방법 중 하나가 더 빠를 수도 있습니다. 첫 번째는 solution offered by Paŭlo Ebermann이지만, 하나의 작은 비틀기와 함께 :

function replace_char2(pos, str, r) 
    return ("%s%s%s"):format(str:sub(1,pos-1), r, str:sub(pos+1)) 
end 

이것은 별도의 임시 개체를 필요없이 최종 버퍼 크기를 추측 할 수있는 희망에 결과의 조립을 할 string.format을 사용합니다.

그러나 은 %s 형식을 통과하는 모든 문자열에서 \0 문자와 관련된 문제가 발생할 수 있습니다. 특히 표준 C의 sprintf() 함수로 구현되므로 \0의 첫 번째 발생시 대체 문자열을 종료 할 것으로 예상하는 것이 타당합니다. (의견에 의해 Delusional Logic 사용자에 의해 고지.)

떠오르는 세번째 대안이있다 :

function replace_char3(pos, str, r) 
    return table.concat{str:sub(1,pos-1), r, str:sub(pos+1)} 
end 

table.concat 효율적 최종 결과에 문자열 목록을 연결. 선택적인 두 번째 인수는 문자열 사이에 삽입 할 텍스트로 여기에 기본값 인 ""이 삽입됩니다.

내 생각 엔 문자열이 크지 않고이 대체를 자주하지 않으면 이러한 방법간에 실제 성능 차이가 나타나지 않을 것입니다. 그러나 저는 이전에 놀랐습니다. 따라서 응용 프로그램의 프로필을 작성하여 병목 현상이 있는지 확인하고 잠재적 솔루션을 신중하게 벤치마킹하십시오.

+1

깊이있는 설명 주셔서 감사합니다 – dotminic

+1

이것은 오래되었습니다. 하지만 내가 작성한 코드에서 사소한 버그를 해결했습니다. ''replace_char2'' 메쏘드는 널 (''\ 0'') 문자를 삽입하지 않는다는 것을 알았습니다. –

+0

@DelusionalLogic 좋은 지적입니다. 'string.format'은 표준 C의'sprintf()'함수를 기반으로하며 NUL 바이트가 내장 된 문제가있을 수 있습니다. – RBerteig

5

당신 글자 13 대신 함수 내에 pos을 사용해야하지만 별개로 좋을 것입니다. 루아 문자열은 불변하므로, 이것보다 훨씬 더 잘할 수는 없습니다.

아마

"%s%s%s":format(str:sub(1,pos-1), r, str:sub(pos+1, str:len()) 

.. 연산자보다 효율적입니다,하지만 나는 그것을 의심 - 그것은, 병목을 측정 (다음 C에서이 교체 기능을 구현하기로 결정) 밝혀합니다.

+1

예'..' 연산자는 새로운 문자열이 모든'..'에 대해 생성되기 때문에 문자열을 연결하는 가장 느린 방법입니다. 가장 빠른 방법은'string.format'과'table.concat'입니다. 매우 큰 문자열이나 여러 연결 작업으로 작업하지 않는 한 눈에 띄는 효과가 발생해서는 안됩니다. 예를 들어, 500MB 이상의 메모리를 사용하여 1MB 파일을 처리하는 스크립트를 입력 줄마다 약 5 개 사용하여 출력을 정렬 및 재구성하는 동안 처리했습니다. 테이블에 문자열을 저장하고 끝에 table.concat을 저장하도록 변경하면 너무 빨라 져서 측정을 방해하지 않습니다. – Arrowmaster

+1

@Arrowmaster : 'a .. b .. c'에는 새로운 문자열이 두 개 (두 개가 아닌) 생성되었거나 단순히 이것을 가정합니까? 원칙적으로 이는 컴파일러/인터프리터가 새로운 문자열을 하나만 생성하도록 최적화 할 수 있습니다. 이는 '+'연산자에 대해 Java에서 수행되는 것과 같습니다. 당신의 예제는 또 다른 경우입니다, 왜냐하면 당신은 정말로 모든 문장으로 새로운 문자열을 생성해야하기 때문입니다. –

+0

@ Paŭlo Ebermann yeah 방금 코드를 복사하고 리터럴을 삭제하는 것을 잊었습니다. @Arrowmaster @ Paŭlo Ebermann .. 연산자를 포맷 메서드와 비교해 보겠습니다. 통찰력에 감사드립니다. – dotminic