我想要的是像
int main()
{
char line[80];
int count;
printf(" Enter a line of text below:\n");
scanf("%[^\n], &line");
for(count=0;line[count]!='\0';++count){
if(((line[count]>='0') && (line[count] < '9'))||
((line[count] >= 'A') && (line[count]< 'Z'))||
((line[count]>= 'a' ) && (line[count] <'z' )))
putchar(line[count]+1);
else if(line[count] =='9' ) putchar('0');
else if(line[count] == 'Z')putchar('A');
else if(line[count] == 'z')putchar('a');
else putchar('.');
}
return 0;
}
结果可能是一个范围或一个元组或其他什么。
我宁愿不做抄袭角色和使用状态机的蛮力。为什么要重新发明词霸?还有更好的方法吗?
答案 0 :(得分:2)
在您的示例中,您的单词是唯一的,您可以使用以下方法:
let myString = "word1 word2 word3"
let wordNum = 2
let myRange = myString.rangeOfString(myString.componentsSeparatedByString(" ")[wordNum-1])
// 6..<11
正如Andrew Duncan在下面的评论中所指出的,只有你的话语是独一无二的,上述内容才有效。如果你有非独特的单词,你可以使用这种不太简洁的方法:
let myString = "word1 word2 word3 word2 word1 word3 word1"
let wordNum = 7 // 2nd instance (out of 3) of "word1"
let arr = myString.componentsSeparatedByString(" ")
var fromIndex = arr[0..<wordNum-1].map { $0.characters.count }.reduce(0, combine: +) + wordNum - 1
let myRange = Range<String.Index>(start: myString.startIndex.advancedBy(fromIndex), end: myString.startIndex.advancedBy(fromIndex+arr[wordNum-1].characters.count))
let myWord = myString.substringWithRange(myRange)
// string "word1" (from range 36..<41)
最后,让我们使用后者构建String
的扩展名,如您在问题示例中所希望的那样:
extension String {
private func rangeOfNthWord(wordNum: Int, wordSeparator: String) -> Range<String.Index>? {
let arr = myString.componentsSeparatedByString(wordSeparator)
if arr.count < wordNum {
return nil
}
else {
let fromIndex = arr[0..<wordNum-1].map { $0.characters.count }.reduce(0, combine: +) + (wordNum - 1)*wordSeparator.characters.count
return Range<String.Index>(start: myString.startIndex.advancedBy(fromIndex), end: myString.startIndex.advancedBy(fromIndex+arr[wordNum-1].characters.count))
}
}
}
let myString = "word1 word2 word3 word2 word1 word3 word1"
let wordNum = 7 // 2nd instance (out of 3) of "word1"
if let myRange = myString.rangeOfNthWord(wordNum, wordSeparator: " ") {
// myRange: 36..<41
print(myString.substringWithRange(myRange)) // prints "word1"
}
如果单词分隔不唯一(例如,某些单词由两个空格.rangeOfNthWord(...)
分隔),则可以调整" "
方法。
在下面的评论中也指出,使用.rangeOfString(...)
本身并不是纯 Swift。然而,这绝不是不好的做法。来自Swift Language Guide - Strings and Characters:
Swift的String类型与Foundation的NSString类桥接。如果 你正在使用Cocoa的Foundation框架,整个 NSString API可用于调用您创建的任何String值 类型转换为NSString,如AnyObject中所述。 您也可以使用 任何需要NSString实例的API的字符串值。
另请参阅NSString class reference for rangeOfString method:
// Swift Declaration:
func rangeOfString(_ searchString: String) -> NSRange
答案 1 :(得分:0)
我继续编写状态机。 (Grumble ..)FWIW,这里是:
extension String {
private func halfOpenIntervalOfBlock(n:Int, separator sep:Character? = nil) -> (Int, Int)? {
enum State {
case InSeparator
case InPrecedingSeparator
case InWord
case InTarget
case Done
}
guard n > 0 else {
return nil
}
var state:State
if n == 1 {
state = .InPrecedingSeparator
} else {
state = .InSeparator
}
var separatorNum = 0
var startIndex:Int = 0
var endIndex:Int = 0
for (i, c) in self.characters.enumerate() {
let inSeparator:Bool
// A bit inefficient to keep doing this test.
if let s = sep {
inSeparator = c == s
} else {
inSeparator = c == " " || c == "\n"
}
endIndex = i
switch state {
case .InPrecedingSeparator:
if !inSeparator {
state = .InTarget
startIndex = i
}
case .InTarget:
if inSeparator {
state = .Done
}
case .InWord:
if inSeparator {
separatorNum += 1
if separatorNum == n - 1 {
state = .InPrecedingSeparator
} else {
state = .InSeparator
}
}
case .InSeparator:
if !inSeparator {
state = .InWord
}
case .Done:
break
}
if state == .Done {
break
}
}
if state == .Done {
return (startIndex, endIndex)
} else if state == .InTarget {
return (startIndex, endIndex + 1) // We ran off end.
} else {
return nil
}
}
func rangeOfWord(n:Int) -> Range<Index>? {
guard let (s, e) = self.halfOpenIntervalOfBlock(n) else {
return nil
}
let ss = self.startIndex.advancedBy(s)
let ee = self.startIndex.advancedBy(e)
return Range(start:ss, end:ee)
}
}