I want to cast some Latin strings to English(PinYin) with swift on Linux,so I wrote a function, but it seems to have some errors in it. It can run in xcode on mac os, but it will go wrong on Linux. I think there are something wrong in the conversion
between CFString and string. I don't know what it is. Can someone help me? Thanks
import Foundation
#if os(Linux)
import CoreFoundation
import Glibc
#endif
public extension String{
func transformToLatinStripDiacritics() -> String{
let nsStr = NSMutableString(string: self)
let str = unsafeBitCast(nsStr, to: CFMutableString.self)
if CFStringTransform(str, nil, kCFStringTransformToLatin, false){
if CFStringTransform(str, nil, kCFStringTransformStripDiacritics, false){
let s = String(describing: unsafeBitCast(str, to: NSMutableString.self) as NSString)
return s
}
return self
}
return self
}
}
As far as I tried on the IBM Swift Sandbox, CFStringTransform does not work on arbitrary CFMutableStrings. Seems it requires CFMutableString based on UTF-16 representation.
import Foundation
#if os(Linux)
import CoreFoundation
import Glibc
#endif
public extension String {
func transformToLatinStripDiacritics() -> String{
let chars = Array(self.utf16)
let cfStr = CFStringCreateWithCharacters(nil, chars, self.utf16.count)
let str = CFStringCreateMutableCopy(nil, 0, cfStr)!
if CFStringTransform(str, nil, kCFStringTransformToLatin, false) {
if CFStringTransform(str, nil, kCFStringTransformStripDiacritics, false) {
return String(describing: str)
}
return self
}
return self
}
}
print("我在大阪住".transformToLatinStripDiacritics()) //->wo zai da ban zhu
Tested only for a few examples. So, this may not be the best solution for your issue.
Related
This code sample was working in a macOS playground:
import Cocoa
import XCPlayground
func getResImg(name: String, ext: String) -> CIImage {
guard let fileURL = Bundle.main.url(forResource: name, withExtension: ext) else {
fatalError("can't find image")
}
guard let img = CIImage(contentsOf: fileURL) else {
fatalError("can't load image")
}
return img
}
var img = getResImg(name: "noise", ext: "jpg")
After upgrading to Swift 4.1 it doesn't. Error: Failed to get a bitmap representation of this NSImage.
How does it work now in Swift 4.1?
I ran into the same issue even though I was using a macOS project and wasn't able to pinpoint what's going wrong here, but I found a workaround which fixes playground rendering for CIImage by using a CustomPlaygroundDisplayConvertible
Just add the following code to the top of your playground and your images will render again
extension CIImage: CustomPlaygroundDisplayConvertible {
static let playgroundRenderContext = CIContext()
public var playgroundDescription: Any {
let jpgData = CIImage.playgroundRenderContext.jpegRepresentation(of: self, colorSpace: CGColorSpace(name: CGColorSpace.sRGB)!, options: [:])!
return NSImage(data: jpgData)!
}
}
public convenience init(nsurl:NSURL) {
var enc:NSStringEncoding = NSUTF8StringEncoding
var err:NSError?
let str:String? =
NSString(
contentsOfURL:nsurl, usedEncoding:&enc, error:&err
)
if err != nil { self.init(err!) }
else { self.init(string:str!) }
}
Swift is version 1.2, error message is:
NSString? is not convertible to string
With Swift 1.2 automatic bridging between String and NSString has been removed.
So you have to explicitly do the cast :
let str = NSString(contentsOfURL:nsurl, usedEncoding:&enc, error:&err) as? String
Swift's String accepts this same initializer as NSString, so you don't even have to use NSString nor to typecast:
let str = String(contentsOfURL: nsurl, encoding: enc, error: &err)
Update for Swift 2.0
do {
let str = try String(contentsOfURL: nsurl, encoding: enc)
print(str)
} catch {
print(error)
}
You can also use an Optional with try? if you want, in this case no need for do catch:
if let str = try? String(contentsOfURL: nsurl, encoding: enc) {
print(str)
} else {
// didn't succeed
}
In Swift 3 I am using the following
do{
let str = try String(contentsOf:personUrl!)
print(str)
}catch let error{
print(error)
}
I need to know if a string contains an Int to be sure that a name the user entered is a valid full name,
for that I need to either make the user type only chars, or valid that there are no ints in the string the user entered.
Thanks for all the help.
You can use Foundation methods with Swift strings, and that's what you should do here. NSString has built in methods that use NSCharacterSet to check if certain types of characters are present. This translates nicely to Swift:
var str = "Hello, playground1"
let decimalCharacters = CharacterSet.decimalDigits
let decimalRange = str.rangeOfCharacter(from: decimalCharacters)
if decimalRange != nil {
print("Numbers found")
}
If you're interested in restricting what can be typed, you should implement UITextFieldDelegate and the method textField(_:shouldChangeCharactersIn:replacementString:) to prevent people from typing those characters in the first place.
Simple Swift 4 version using rangeOfCharacter method from String class:
let numbersRange = stringValue.rangeOfCharacter(from: .decimalDigits)
let hasNumbers = (numbersRange != nil)
This method is what i use now for checking if a string contains a number
func doStringContainsNumber( _string : String) -> Bool{
let numberRegEx = ".*[0-9]+.*"
let testCase = NSPredicate(format:"SELF MATCHES %#", numberRegEx)
let containsNumber = testCase.evaluateWithObject(_string)
return containsNumber
}
If your string Contains a number it will return true else false. Hope it helps
//Swift 3.0 to check if String contains numbers (decimal digits):
let someString = "string 1"
let numberCharacters = NSCharacterSet.decimalDigits
if someString.rangeOfCharacter(from: numberCharacters) != nil
{ print("String contains numbers")}
else if someString.rangeOfCharacter(from: numberCharacters) == nil
{ print("String doesn't contains numbers")}
//A function that checks if a string has any numbers
func stringHasNumber(_ string:String) -> Bool {
for character in string{
if character.isNumber{
return true
}
}
return false
}
/// Check stringHasNumber function
stringHasNumber("mhhhldiddld")
stringHasNumber("kjkdjd99900")
if (ContainsNumbers(str).count > 0)
{
// Your string contains at least one number 0-9
}
func ContainsNumbers(s: String) -> [Character]
{
return s.characters.filter { ("0"..."9").contains($0)}
}
Swift 2.3. version working.
extension String
{
func containsNumbers() -> Bool
{
let numberRegEx = ".*[0-9]+.*"
let testCase = NSPredicate(format:"SELF MATCHES %#", numberRegEx)
return testCase.evaluateWithObject(self)
}
}
Usage:
//guard let firstname = textField.text else { return }
let testStr1 = "lalalala"
let testStr2 = "1lalalala"
let testStr3 = "lal2lsd2l"
print("Test 1 = \(testStr1.containsNumbers())\nTest 2 = \(testStr2.containsNumbers())\nTest 3 = \(testStr3.containsNumbers())\n")
You need to trick Swift into using Regex by wrapping up its nsRegularExpression
class Regex {
let internalExpression: NSRegularExpression
let pattern: String
init(_ pattern: String) {
self.pattern = pattern
var error: NSError?
self.internalExpression = NSRegularExpression(pattern: pattern, options: .CaseInsensitive, error: &error)
}
func test(input: String) -> Bool {
let matches = self.internalExpression.matchesInString(input, options: nil, range:NSMakeRange(0, countElements(input)))
return matches.count > 0
}
}
if Regex("\\d/").test("John 2 Smith") {
println("has a number in the name")
}
I got these from http://benscheirman.com/2014/06/regex-in-swift/
let numericCharSet = CharacterSet.init(charactersIn: "1234567890")
let newCharSet = CharacterSet.init(charactersIn: "~`##$%^&*(){}[]<>?")
let sentence = "Tes#ting4 #Charact2er1Seqt"
if sentence.rangeOfCharacter(from: numericCharSet) != nil {
print("Yes It,Have a Numeric")
let removedSpl = sentence.components(separatedBy: newCharSet).joined()
print(sentence.components(separatedBy: newCharSet).joined())
print(removedSpl.components(separatedBy: numericCharSet).joined())
}
else {
print("No")
}
Say for example you have something like this, trying to make the example as simple as possible.
type Home struct {
Bedroom string
Bathroom string
}
How do you pass the field name, or can you, to a function?
func (this *Home) AddRoomName(fieldname, value string) {
this.fieldname = value
}
Obviously that does not work... The only way I can see to do this is to use two functions which adds a lot of extra code when the struct gets really big and has a lot of similar code.
func (this *Home) AddBedroomName(value string) {
this.Bedroom = value
}
func (this *Home) AddBathroomName(value string) {
this.Bathroom = value
}
The only way that I am aware of is to use reflection:
func (this *Home) AddRoomName(fieldname, value string) {
h := reflect.ValueOf(this).Elem()
h.FieldByName(fieldname).Set(reflect.ValueOf(value))
return
}
http://play.golang.org/p/ZvtF_05CE_
One more idea that comes to my mind is like this, not sure if it makes sense in your case though:
func Set(field *string, value string) {
*field = value
}
home := &Home{"asd", "zxc"}
fmt.Println(home)
Set(&home.Bedroom, "bedroom")
Set(&home.Bathroom, "bathroom")
fmt.Println(home)
http://play.golang.org/p/VGb69OLX-X
Use type assertions on an interface value:
package main
import "fmt"
type Test struct {
S string
I int
}
func (t *Test) setField(name string, value interface{}) {
switch name {
case "S":
t.S = value.(string)
case "I":
t.I = value.(int)
}
}
func main() {
t := &Test{"Hello", 0}
fmt.Println(t.S, t.I)
t.setField("S", "Goodbye")
t.setField("I", 1)
fmt.Println(t.S, t.I)
}
I would like to emulate C's sprintf("%02d", x); in Dart, but I can't find string formatting, only string interpolation.
String interpolation covers most of your needs. If you want to format numbers directly, there is also num.toStringAsPrecision().
I took a different approach to this issue: by padding the string directly, I don't have to use any libraries (mainly because the intl library seems to be discontinued):
x.toString().padLeft(2, "0");
Would be the equivalent of sprintf("%02d", x);
The intl library provides several helpers to format values.
See the API documentation at http://api.dartlang.org/docs/releases/latest/intl.html
Here is an example on how to convert a number into a two character string:
import 'package:intl/intl.dart';
main() {
var twoDigits = new NumberFormat("00", "en_US");
print(twoDigits.format(new Duration(seconds: 8)));
}
A String.format method does not currently exists but there is a bug/feature request for adding it.
Here is my implementation of String.format for Dart. It is not perfect but works good enough for me:
static String format(String fmt,List<Object> params) {
int matchIndex = 0;
String replace(Match m) {
if (matchIndex<params.length) {
switch (m[4]) {
case "f":
num val = params[matchIndex++];
String str;
if (m[3]!=null && m[3].startsWith(".")) {
str = val.toStringAsFixed(int.parse(m[3].substring(1)));
} else {
str = val.toString();
}
if (m[2]!=null && m[2].startsWith("0")) {
if (val<0) {
str = "-"+str.substring(1).padLeft(int.parse(m[2]),"0");
} else {
str = str.padLeft(int.parse(m[2]),"0");
}
}
return str;
case "d":
case "x":
case "X":
int val = params[matchIndex++];
String str = (m[4]=="d")?val.toString():val.toRadixString(16);
if (m[2]!=null && m[2].startsWith("0")) {
if (val<0) {
str = "-"+str.substring(1).padLeft(int.parse(m[2]),"0");
} else {
str = str.padLeft(int.parse(m[2]),"0");
}
}
return (m[4]=="X")?str.toUpperCase():str.toLowerCase();
case "s":
return params[matchIndex++].toString();
}
} else {
throw new Exception("Missing parameter for string format");
}
throw new Exception("Invalid format string: "+m[0].toString());
}
Test output follows:
format("%d", [1]) // 1
format("%02d", [2]) // 02
format("%.2f", [3.5]) // 3.50
format("%08.2f", [4]) // 00004.00
format("%s %s", ["A","B"]) // A B
format("%x", [63]) // 3f
format("%04x", [63]) // 003f
format("%X", [63]) //3F
Yes, Dart has a sprintf package:
https://pub.dev/packages/sprintf.
It is modeled after C's sprintf.
See a format package. It is similar to format() from Python. It is a new package. Needs testing.