I have to decode file encoded in ASCII. However when I want to decode the file, i get a "?" instead of "é" that testify that the decoding didn't happen properly.
This is the code that I am using. Which condition should I had to properly encode ASCII ?
- (void)_sniffEncoding {
NSStringEncoding encoding = NSUTF8StringEncoding;
uint8_t bytes[CHUNK_SIZE];
NSInteger readLength = [_stream read:bytes maxLength:CHUNK_SIZE];
if (readLength > 0 && readLength <= CHUNK_SIZE) {
[_stringBuffer appendBytes:bytes length:readLength];
[self setTotalBytesRead:[self totalBytesRead] + readLength];
NSInteger bomLength = 0;
if (readLength > 3 && bytes[0] == 0x00 && bytes[1] == 0x00 && bytes[2] == 0xFE && bytes[3] == 0xFF) {
encoding = NSUTF32BigEndianStringEncoding;
bomLength = 4;
} else if (readLength > 3 && bytes[0] == 0xFF && bytes[1] == 0xFE && bytes[2] == 0x00 && bytes[3] == 0x00) {
encoding = NSUTF32LittleEndianStringEncoding;
bomLength = 4;
} else if (readLength > 3 && bytes[0] == 0x1B && bytes[1] == 0x24 && bytes[2] == 0x29 && bytes[3] == 0x43) {
encoding = CFStringConvertEncodingToNSStringEncoding(kCFStringEncodingISO_2022_KR);
bomLength = 4;
} else if (readLength > 1 && bytes[0] == 0xFE && bytes[1] == 0xFF) {
encoding = NSUTF16BigEndianStringEncoding;
bomLength = 2;
} else if (readLength > 1 && bytes[0] == 0xFF && bytes[1] == 0xFE) {
encoding = NSUTF16LittleEndianStringEncoding;
bomLength = 2;
} else if (readLength > 2 && bytes[0] == 0xEF && bytes[1] == 0xBB && bytes[2] == 0xBF) {
encoding = NSUTF8StringEncoding;
bomLength = 3;
} else {
NSString *bufferAsUTF8 = nil;
for (NSInteger triedLength = 0; triedLength < 4; ++triedLength) {
bufferAsUTF8 = [[NSString alloc] initWithBytes:bytes length:readLength-triedLength encoding:NSUTF8StringEncoding];
if (bufferAsUTF8 != nil) {
break;
}
}
if (bufferAsUTF8 != nil) {
encoding = NSUTF8StringEncoding;
} else {
NSLog(#"unable to determine stream encoding; assuming MacOSRoman");
encoding = NSMacOSRomanStringEncoding;
}
}
if (bomLength > 0) {
[_stringBuffer replaceBytesInRange:NSMakeRange(0, bomLength) withBytes:NULL length:0];
}
}
_streamEncoding = encoding;
}
Related
ObjC code:
#pragma mark - bookNameFromString
+(NSString *) bookNameFromString:(NSString *)string{
NSMutableArray *newLineArray = [[NSMutableArray alloc]init];
NSUInteger length = [string length];
unichar buffer[length+1];
[string getCharacters:buffer range:NSMakeRange(0, length)];
NSInteger a = 0;
do {
a = a+ 1;
char current = buffer[a];
if (current == '\n') {
[newLineArray addObject:[NSNumber numberWithInteger:a]];
break;
}
} while (a <= length);
NSString *bookName = nil;
if (newLineArray.count > 0 && newLineArray[0] != 0) {
bookName = [string substringToIndex:[newLineArray[0]integerValue]];
}
return bookName;
}
In Swift:
While converting to swift
How to create string buffer as done in objC.
While appending value to array, there is an error: Cannot convert value of type 'String.CharacterView.Index' to expected argument type 'Int'
// MARK: - bookNameFromString
func bookNameFromString(string:String) ->String {
let toFind:Character = "\n"
var newLineArray:[Int] = []
let lengthOfString = string.characters.count
var a = 0
repeat{
a = a + 1
if let index = string.characters.indexOf(toFind) {
newLineArray.append(index) */ERROR: Cannot convert value of type 'String.CharacterView.Index' to expected argument type 'Int'/*
break
}
}while a < lengthOfString
print(newLineArray)
var bookName:String
if newLineArray.count > 0 && newLineArray[0] != 0{
bookName = string.substringToIndex(string.startIndex.advancedBy(newLineArray[0]))
}
return bookName
}
This is an attempt of an approach without buffers and checking single characters
func bookNameFromString(string : String) -> String?
{
// separate string by linefeed character
let array = string.componentsSeparatedByString("\n")
// if string is empty or there is none or one linefeed - exit
guard array.count > 1 else { return nil }
// define a startindex which is 1 if the string starts with linefeed
let startIndex = array[0].isEmpty ? 1 : 0
// if there is no linefeed left - exit
guard array.count > startIndex + 1 else { return nil }
return startIndex == 1 ? "\n" + array[startIndex] : array[startIndex]
}
bookNameFromString("") // -> nil
bookNameFromString("\n") // -> nil
bookNameFromString("\n\n") // -> \n
bookNameFromString("Hello") // -> nil
bookNameFromString("\nHello") // -> nil
bookNameFromString("Hello\n") // -> Hello
bookNameFromString("Hello\nWorld") // -> Hello
bookNameFromString("\nHello\n") // -> \nHello
bookNameFromString("\nHello\nWorld") // -> \nHello
Some value of col in sqlite database:
a1b2
a2b3
a1b10
a10b1
if use order by in sql it will be:
a10b1
a1b10
a1b2
a2b3
I want it like NSNumericSearch of objc like this:
a1b2
a1b10
a2b3
a10b1
How do I write the SQL statements?
Start by creating a custom collating function:
int compare_natural(void *data, int len1, const void *str1, int len2, const void *str2) {
if (str1 && len1 > 0 && str2 && len2 > 0) {
NSString *s1 = [[NSString alloc] initWithBytesNoCopy:(void *)str1 length:len1 encoding:NSUTF8StringEncoding freeWhenDone:NO];
NSString *s2 = [[NSString alloc] initWithBytesNoCopy:(void *)str2 length:len2 encoding:NSUTF8StringEncoding freeWhenDone:NO];
// The use of NSNumericSearch is required for your need.
// The others are options depending on your needs
NSComparisonResult res = [s1 compare:s2 options:NSCaseInsensitiveSearch | NSNumericSearch | NSDiacriticInsensitiveSearch];
return res;
} else if (str1 && len1 > 0 && (!str2 || len2 == 0)) {
return -1; // empty strings to the end of the list (optional)
} else if (str2 && len2 > 0 && (!str1 || len1 == 0)) {
return 1; // empty strings to the end of the list (optional)
} else {
return 0;
}
}
Then register the custom collator. This needs to be done after you open the database.
// dbRef is your sqlite3 database reference
int rc = sqlite3_create_collation(dbRef, "BYNUMBER", SQLITE_UTF8, NULL, &compare_natural);
Then update your query so it ends with "COLLATE BYNUMBER"
SELECT some_col ORDER BY some_col COLLATE BYNUMBER;
I've coded a 2-Player TicTacToe game using command line. Code works when player 1 wins in 3 moves, however after player 1 makes their 3rd mark, the game ends saying that "Player 1 wins" even if they haven't won. I'm new to coding so I know its not the prettiest or shortest way to do this.
NSInteger chosen = 0;
NSInteger player = 1;
NSInteger winner = 0;
NSInteger row = 0;
NSInteger column = 0;
NSInteger arr[4][4] = {{0, 0, 0, 0},
{0, 0, 0, 0},
{0, 0, 0, 0},
{0, 0, 0, 0}};
int main(int argc, const char * argv[])
{
//display new board
NSLog(#"%ld %ld %ld ",arr[1][1], arr[1][2],arr[1][3]);
NSLog(#"%ld %ld %ld ",arr[2][1], arr[2][2],arr[2][3]);
NSLog(#"%ld %ld %ld ",arr[3][1], arr[3][2],arr[3][3]);
do
{
if (player == 1)
{
//player 1's input
NSLog(#"Player 1, please choose a cell.");
NSLog(#"Enter row number(1, 2, or 3).");
scanf("%ld", &row);
NSLog(#"Enter column number(1, 2, or 3).");
scanf("%ld", &column);
//add input to board
arr [row][column] = 1;
//display updated board
NSLog(#"%ld %ld %ld ",arr[1][1], arr[1][2],arr[1][3]);
NSLog(#"%ld %ld %ld ",arr[2][1], arr[2][2],arr[2][3]);
NSLog(#"%ld %ld %ld ",arr[3][1], arr[3][2],arr[3][3]);
chosen++;
//check for winner
if ((arr[1][1] && arr[2][1] && arr[3][1]) == 1) {
winner = 1;
} else if ((arr[1][2] && arr[2][2] && arr[3][2]) == 1) {
winner = 1;
} else if ((arr[1][3] && arr[2][3] && arr[3][3]) == 1) {
winner = 1;
} else if ((arr[1][1] && arr[1][2] && arr[1][3]) == 1) {
winner = 1;
} else if ((arr[2][1] && arr[2][2] && arr[2][3]) == 1) {
winner = 1;
} else if ((arr[3][1] && arr[3][2] && arr[3][3]) == 1) {
winner = 1;
} else if ((arr[3][1] && arr[2][2] && arr[1][3]) == 1) {
winner = 1;
} else if ((arr[1][1] && arr[2][2] && arr[3][3]) == 1) {
winner = 1;
} else player++;
}
if (player == 2)
{
//player 2's input
NSLog(#"Player 2, please choose a cell.");
NSLog(#"Enter row number(1, 2, or 3).");
scanf("%ld", &row);
NSLog(#"Enter column number(1, 2, or 3).");
scanf("%ld", &column);
//add input to board
arr [row][column] = 2;
//display updated board
NSLog(#"%ld %ld %ld ",arr[1][1], arr[1][2],arr[1][3]);
NSLog(#"%ld %ld %ld ",arr[2][1], arr[2][2],arr[2][3]);
NSLog(#"%ld %ld %ld ",arr[3][1], arr[3][2],arr[3][3]);
//add a
chosen++;
if ((arr[1][1] && arr[2][1] && arr[3][1]) == 2) {
winner = 2;
} else if ((arr[1][2] && arr[2][2] && arr[3][2]) == 2) {
winner = 2;
} else if ((arr[1][3] && arr[2][3] && arr[3][3]) == 2) {
winner = 2;
} else if ((arr[1][1] && arr[1][2] && arr[1][3]) == 2) {
winner = 2;
} else if ((arr[2][1] && arr[2][2] && arr[2][3]) == 2) {
winner = 2;
} else if ((arr[3][1] && arr[3][2] && arr[3][3]) == 2) {
winner = 2;
} else if ((arr[3][1] && arr[2][2] && arr[1][3]) == 2) {
winner = 2;
} else if ((arr[1][1] && arr[2][2] && arr[3][3]) == 2) {
winner = 2;
} else player--;
}
//player 1 wins
if (winner == 1) {
NSLog(#"Player 1 won");
return 0;
}
//player 2 wins
if (winner == 2) {
NSLog(#"Player 2 won");
return 0;
}
} while (chosen < 9);
//no winner
NSLog(#"Draw");
return 0;
}
All your comparisons are wrong. Instead of
if ((arr[1][1] && arr[2][2] && arr[3][3]) == 1)
Do
if (arr[1][1]==1 && arr[2][2]==1 && arr[3][3] == 1) {
For player 1. For player 2, use ==2 instead of ==1.
Because arr[1][1] by itself will be true if the value is not zero...
As it is, since true is usually represented as 1, your condition will say player 1 wins whenever there are three tokens in a row (regardless of what they are).
I want to know the text file encoding in objective-c. Can you explain me how to know that?
You can use stringWithContentsOfFile:usedEncoding:error:, which returns, in addition to the new string, the encoding that was used.
I should note that this is a heuristic process by nature -- it's not always possible to determine the character encoding of a file.
Some text document show the gibberish in my project, so I need to know the encoding of the text file, to change its encoding, let it can be read by human.
I found this : http://lists.w3.org/Archives/Public/www-validator/2002Aug/0084.html
and Using OC to rewrite code,it can work for me:
NSString *documentPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject];
NSString *sourceFilePath = [documentPath stringByAppendingPathComponent:#"fileName.txt"];
NSFileHandle *sourceFileHandle = [NSFileHandle fileHandleForReadingAtPath:sourceFilePath];
NSData *begainData = [sourceFileHandle readDataOfLength:3];
Byte *bytes = (Byte *)[begainData bytes];
if (bytes[0] == 0xff
&& bytes[1] == 0xfe
&& (begainData.length < 4
|| bytes[2] != 0
|| bytes[3] != 0
)
)
{
NSLog(#"unicode");
}
if (bytes[0] == 0xfe
&& bytes[1] == 0xff
)
NSLog(#"BigEndianUnicode");
if (bytes[0] == 0xef && bytes[1] == 0xbb && bytes[2] == 0xbf)
NSLog(#"UTF8");
if (bytes[0] == 0x2b && bytes[1] == 0x2f && bytes[2] == 0x76)
NSLog(#"UTF7");
if (bytes[0] == 0xff && bytes[1] == 0xfe && bytes[2] == 0 && bytes[3] == 0)
NSLog(#"UTF32");
if (begainData.length < 3)
NSLog(#"ascii");
I want to fetch the machine's serial number key. Does any body help me on how to fetch the machine's serial number?
There is no Cocoa API for this. You have to call into Carbon.
#import <Carbon/Carbon.h>
#import<IOKit/IOKitLib.h>
#import <mach/mach.h>
NSString* UKSystemSerialNumber()
{
mach_port_t masterPort;
kern_return_t kr = noErr;
io_registry_entry_t entry;
CFTypeRef prop;
CFTypeID propID;
NSString* str = nil;
kr = IOMasterPort(MACH_PORT_NULL, &masterPort);
if( kr != noErr )
goto cleanup;
entry = IORegistryGetRootEntry( masterPort );
if( entry == MACH_PORT_NULL )
goto cleanup;
prop = IORegistryEntrySearchCFProperty(entry, kIODeviceTreePlane, CFSTR("serial-number"), nil, kIORegistryIterateRecursively);
if( prop == nil )
goto cleanup;
propID = CFGetTypeID( prop );
if( propID != CFDataGetTypeID() )
goto cleanup;
const char* buf = [(NSData*)prop bytes];
int len = [(NSData*)prop length],
x;
char secondPart[256];
char firstPart[256];
char* currStr = secondPart; // Version number starts with second part, then NULLs, then first part.
int y = 0;
for( x = 0; x < len; x++ )
{
if( buf[x] > 0 && (y < 255) )
currStr[y++] = buf[x];
else if( currStr == secondPart )
{
currStr[y] = 0; // Terminate string.
currStr = firstPart;
y = 0;
}
}
currStr[y] = 0; // Terminate string.
str = [NSString stringWithFormat: #"%s%s", firstPart, secondPart];
cleanup:
mach_port_deallocate( mach_task_self(), masterPort );
return str;
}
The above code comes from here
This is from Technical Note TN1103
#include <CoreFoundation/CoreFoundation.h>
#include <IOKit/IOKitLib.h>
// Returns the serial number as a CFString.
// It is the caller's responsibility to release the returned CFString when done with it.
void CopySerialNumber(CFStringRef *serialNumber)
{
if (serialNumber != NULL) {
*serialNumber = NULL;
io_service_t platformExpert = IOServiceGetMatchingService(kIOMasterPortDefault,
IOServiceMatching("IOPlatformExpertDevice"));
if (platformExpert) {
CFTypeRef serialNumberAsCFString =
IORegistryEntryCreateCFProperty(platformExpert,
CFSTR(kIOPlatformSerialNumberKey),
kCFAllocatorDefault, 0);
if (serialNumberAsCFString) {
*serialNumber = serialNumberAsCFString;
}
IOObjectRelease(platformExpert);
}
}
}
I'd be careful though, it mentions some caveats about not making any assumptions about the S/N length or anything