2012-09-02 2 views
4

내가 들어오는 문자열에 내가 "나쁜"단어 중 하나를 포함하고 있는지 검색하려고한다고 가정 해보십시오. :)이 경우 정규식이 배열 비교보다 빠릅니까?

문자열을 배열로 분할하고 나쁜 단어를 배열에 보관 한 다음 각 잘못된 단어와 각 수신 단어를 반복하여 일치하는 항목이 있는지 확인하는 것이 더 빠릅니까? 같은 :

badwords.each do |badword| 
incoming.each do |word| 
    trigger = true if badword == word 
end 
end 

또는 더 빨리이 작업을 수행하는 것입니다

incoming.each do |word| 
trigger = true if badwords.include? word 
end 

을하거나 그대로 문자열을 떠나 같은 형태의 정규식과 .match()를 실행하는 빠른 :

/\bbadword1\b|\bbadword2\b|\bbadword3\b/ 

성능 차이가 거의 무시할 수 있습니까? 잠시 궁금해하고있었습니다.

+8

궁금한 점을 멈추고 측정을 시작하십시오. –

답변

5

일치 항목을 찾으면 루프를 멈추지 않아도 정규식에 이점이 있습니다. 시도 :

/\b(badword1|badword2|badword3)\b/ 

또는 그것에게 공정한 싸움을 만드는 :

incoming.find{|word| badwords.include? word} 

내 돈이 정규식에 여전히 어떤 불구하고 단순화해야

/\a(badword1|badword2|badword3)\z/ 
+1

캡처하지 않은 그룹을 사용하여 약간의 성능 향상을 얻을 수 있습니다. –

+0

환상적입니다. .find가 ruby ​​docs Array # find에서 메소드로 나열되지 않은 이유를 설명해 주시겠습니까? –

+0

예, 배열에 포함 된 Enumerable 모듈의 일부입니다. – pguardiario

3

일단 컴파일되면 Regex는 incomingin situ에서 실행될 수 있기 때문에 실제 라이브 (즉, 실제로 긴 수신 문자열, 많은 유사한 불량 단어 등)에서 가장 빠르며 "나쁜 단어"의 중복 부분을 처리합니다. 정말 잘.

2

대답은 아마도에 따라 달라집니다 검사 할 불량 단어의 수 : 불량 단어가 하나뿐이라면 큰 차이는 없을 것입니다. 50 개가 있다면 배열 검사가 느려질 수 있습니다. 반면에 수십 또는 수십만 단어의 정규 표현식은 너무 빠르지 않을 것입니다

많은 수의 불량 단어를 처리해야하는 경우 개별 단어로 분리 한 다음 그 말의 악성 여부를 테스트하는 bloomfilter.

2

이 질문에 대한 답변이 유용하지는 않지만 분명히 해결할 수 있습니다.

귀하가 습득해야 할 것들을 벤치 마크에 두십시오.

당신은 루비에서 벤치마킹을 수행하는 방법을 찾을 수 있습니다 here

그냥 보고서 블록 사이의 varoius 양식을 넣고 벤치 마크를 취득하고 당신에게 가장 적합한 것을 스스로 결정한다. 더 나은 솔루션을

http://ruby-doc.org/stdlib-1.9.3/libdoc/benchmark/rdoc/Benchmark.html

http://ruby.about.com/od/tasks/f/benchmark.htm 테스트하기 위해 실제 데이터를 사용합니다.당신이 단어의 발생에 대한 문자열을 스캔을 찾을 scan를 사용하려면

벤치 마크는 항상 토론 :

1

보다는 더 낫다.

Regexp.union을 사용하면 블랙리스트에 문자열을 찾는 패턴을 만들 수 있습니다. 결과를 \b으로 랩핑하여 단어 경계를 일치 시키며 대소 문자를 구분하지 않는 검색을 사용하고자 할 것입니다. 한 마디로

Regexp.new('\b(?:' + words.join('|') + ')\b', Regexp::IGNORECASE) 
=> /\b(?:foo|bar)\b/i 

/\b(?:#{words.join('|')})\b/i 
=> /\b(?:foo|bar)\b/i 

'Daniel Foo killed him a bar'.scan(/\b(?:#{words.join('|')})\b/i) 
=> ["Foo", "bar"] 

: 당신이 좀 더 컨트롤을 원하는 경우

words = %w[foo bar] 

Regexp.union(words) 
=> /foo|bar/ 

'Daniel Foo killed him a bar'.scan(/\b#{Regexp.union(words)}\b/i) 
=> ["foo", "bar"] 

또한 Regexp.new 또는 /.../를 사용하여 패턴을 만들 수 :

당신에게 Regexp.union 도울 수있는 방법에 대한 아이디어를 제공하려면 당신이 공세감을 느낀 블랙리스트 단어는 사용자가 쉽게 속여서 많은 "불쾌감을주는"단어가 특정 상황에서만 불쾌감을주기 때문에 종종 잘못된 결과를줍니다. 사용자는 의도적으로 철자를 잘못 철자하거나 "l33t"를 사용하고 철자를 거의 다 써서 철자를 바꿀 수 있습니다. 어떤 사람들은 시스템을 속일 수있는 즐거움의 원천입니다.

나는 비슷한 과제를 부여 받았으며 "불쾌한"단어에 대한 대체 철자를 제공하는 번역자를 썼다. 나는 인터넷에서 수집 한 단어와 용어 목록으로 시작하여 코드 실행을 시작했습니다. 몇 백만 개의 대체품이 데이터베이스에 추가 된 후에 나는 플러그를 뽑아 관리를 보여주었습니다. 어리석은 일로 사소한 일 이었기 때문에 바보 같은 일이었습니다.

+0

팁이 좋습니다. 내 경우에는 단어를 필터링하지 않고 단순히 검색 만하면됩니다.이 경우 쿼리에 장난 단어가 포함되어 있으면 다른 결과를 제공해야합니다. –

관련 문제