Six String Operations in Five Languages

This is my favorite way to choose a new language for a project: Implement some code that I need to write in several. Then I ask myself, “which would I rather see and work with”?

  1. Python
  2. Haskell
  3. Elixir
  4. Swift
  5. Ruby
  6. Racket

Python

from typing import Generator
def clean_up(s: str) -> str:
return next(split_into_sentences(fix_hyphenation(fix_whitespace(s))))
def fix_whitespace(s: str) -> str:
return s.replace("\n", " ")
def fix_hyphenation(s: str) -> str:
return s.replace("- ", "")
def split_into_sentences(s: str) -> Generator[str, None, None]:
return (ensure_ends_with_period(sentence) for sentence in s.split(". "))
def ensure_ends_with_period(sentence: str) -> str:
return sentence + ("" if sentence.endswith(".") else ".")
view raw string_ops.py hosted with ❤ by GitHub

Haskell

module StringOps(cleanUp, fixHyphenation, fixWhitespace) where
import Data.List (isSuffixOf)
import Data.String.Utils (replace, split)
cleanUp String String
cleanUp = fixWhitespace
>>> fixHyphenation
>>> splitIntoSentences
>>> first
fixWhitespace String String
fixWhitespace = replace "\n" " "
fixHyphenation String String
fixHyphenation = replace "- " ""
splitIntoSentences String [String]
splitIntoSentences = split ". " map ensureEndsWithPeriod
ensureEndsWithPeriod :: String -> String
ensureEndsWithPeriod sentence =
sentence ++ (if "." `isSuffixOf` sentence then "" else ".")
view raw StringOps.hs hosted with ❤ by GitHub
module StringOpsSpec where
import StringOps
import Test.Hspec
main :: IO ()
main = hspec spec
spec :: Spec
spec = do
describe "fixHyphenation" $ do
it "rejoins a word" $ do
fixHyphenation "auto- mobile" `shouldBe` "automobile"
describe "fixWhitespace" $ do
it "changes a newline to a space" $ do
fixWhitespace "and\nthe story" `shouldBe` "and the story"
describe "cleanUp" $ do
it "handles extra text" $ do
let input = "Relating to the state transient lodging tax; creating\nnew provisions; amending ORS 284.131 and\n320.305; prescribing an effective date; and pro-\nviding for revenue raising that requires approval\nby a three-fifths majority.\nWhereas Enrolled House Bill 2267 (chapter 818,"
cleanUp input `shouldBe` "Relating to the state transient lodging tax; creating new provisions; amending ORS 284.131 and 320.305; prescribing an effective date; and providing for revenue raising that requires approval by a three-fifths majority."

Elixir

import String
defmodule StringOps do
def clean_up(title) do
title
|> fixWhitespace
|> fixHyphenation
|> splitIntoSentences
|> List.first
end
def fixWhitespace(s), do: replace(s, "\n", " ")
def fixHyphenation(s), do: replace(s, "- ", "")
def splitIntoSentences(a_string) do
a_string
|> split(". ")
|> Enum.map(&ensure_ends_with_period/1)
end
def ensure_ends_with_period(sentence) do
sentence <> if ends_with?(sentence, "."), do: "", else: "."
end
end
view raw string_ops.ex hosted with ❤ by GitHub
import StringOps
defmodule StringOpsTest do
use ExUnit.Case
test "fixHyphenation rejoins a word" do
assert fixHyphenation("auto- mobile") == "automobile"
end
test "fixWhitespace changes a newline to a space" do
assert fixWhitespace("and\nthe story") == "and the story"
end
test "clean_up handles extra text" do
input = "Relating to the state transient lodging tax; creating\nnew provisions; amending ORS 284.131 and\n320.305; prescribing an effective date; and pro-\nviding for revenue raising that requires approval\nby a three-fifths majority.\nWhereas Enrolled House Bill 2267 (chapter 818,"
assert clean_up(input) == "Relating to the state transient lodging tax; creating new provisions; amending ORS 284.131 and 320.305; prescribing an effective date; and providing for revenue raising that requires approval by a three-fifths majority."
end
end

Swift

func cleanUp(s: String) -> String {
return splitIntoSentences(summary: fixHyphenation(s: fixWhitespace(s: s)))[0]
}
func fixHyphenation(s: String) -> String {
return s.replacingOccurrences(of: "- ", with: "")
}
func fixWhitespace(s: String) -> String {
return s.replacingOccurrences(of: "\n", with: " ")
}
func splitIntoSentences(summary: String) -> [String] {
return summary
.components(separatedBy: ". ")
.map { ensureEndsWithPeriod(sentence: $0) }
}
func ensureEndsWithPeriod(sentence: String) -> String {
if let lastCharacter = sentence.characters.last {
if lastCharacter == "." {
return sentence
} else {
return sentence + "."
}
} else {
return sentence
}
}
import XCTest
class Tests: XCTestCase {
func testFixHyphenation() {
XCTAssertEqual( fixHyphenation(s: "auto- mobile"), "automobile" )
}
func testFixWhitespace() {
XCTAssertEqual( fixWhitespace(s: "and\nthe story"), "and the story" )
}
func testCleanUp() {
let input = "Relating to the state transient lodging tax; creating\nnew provisions; amending ORS 284.131 and\n320.305; prescribing an effective date; and pro-\nviding for revenue raising that requires approval\nby a three-fifths majority.\nWhereas Enrolled House Bill 2267 (chapter 818,"
let expected_output = "Relating to the state transient lodging tax; creating new provisions; amending ORS 284.131 and 320.305; prescribing an effective date; and providing for revenue raising that requires approval by a three-fifths majority."
XCTAssertEqual( cleanUp(s: input), expected_output )
}
}

Ruby

module StringOps
module_function
def clean_up(summary:)
split_into_sentences(fix_hyphenation(fix_whitespace(summary))).first
end
def fix_whitespace(a_string)
a_string.gsub "\n", " "
end
def fix_hyphenation(a_string)
a_string.gsub "- ", ""
end
def split_into_sentences(a_string)
a_string
.split(". ")
.map { |sentence| ensure_ends_with_period(sentence) }
end
def ensure_ends_with_period(sentence)
sentence + (sentence.end_with?(".") ? "" : ".")
end
end
view raw string_ops.rb hosted with ❤ by GitHub
require 'string_ops'
include StringOps
describe StringOps do
describe '#fix_whitespace' do
it 'changes newline to a blank' do
expect( fix_whitespace "new\nline" ).to eq 'new line'
end
end
describe '#fix_hyphenation' do
it 'de-hyphenates' do
expect( fix_hyphenation 'zip- per' ).to eq 'zipper'
end
end
describe '#clean_up' do
it "handles extra text" do
input = "Relating to the state transient lodging tax; creating\nnew provisions; amending ORS 284.131 and\n320.305; prescribing an effective date; and pro-\nviding for revenue raising that requires approval\nby a three-fifths majority.\nWhereas Enrolled House Bill 2267 (chapter 818,"
expect( clean_up summary: input ).to eq "Relating to the state transient lodging tax; creating new provisions; amending ORS 284.131 and 320.305; prescribing an effective date; and providing for revenue raising that requires approval by a three-fifths majority."
end
end
end

Racket

Thanks to Raevnos for the Racket code:

#lang racket
(define (clean-up s)
(first (split-into-sentences (fix-hyphenation (fix-whitespace s)))))
(define (fix-whitespace s)
(string-replace s "\n" " "))
(define (fix-hyphenation s)
(string-replace s "- " ""))
(define (split-into-sentences s)
(map ensure-ends-with-period (string-split s ". ")))
(define (ensure-ends-with-period s)
(if (char=? (string-ref s (- (string-length s) 1)) #\.)
s
(string-append s ".")))
view raw string_ops.rkt hosted with ❤ by GitHub
(module+ test
(require rackunit)
(check-equal? (fix-whitespace "new\nline") "new line")
(check-equal? (fix-hyphenation "auto- mobile") "automobile")
(check-equal? (clean-up "Relating to the state transient lodging tax; creating\nnew provisions; amending ORS 284.131 and\n320.305; prescribing an effective date; and pro-\nviding for revenue raising that requires approval\nby a three-fifths majority.\nWhereas Enrolled House Bill 2267 (chapter 818,")
"Relating to the state transient lodging tax; creating new provisions; amending ORS 284.131 and 320.305; prescribing an effective date; and providing for revenue raising that requires approval by a three-fifths majority."))

Leave a Comment

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s