Currently using Dart with gsheets_api, which don't seem to have a function to convert column letters to numbers (column index)
As an example , this is what I use with AppScript (input: column letter, output: column index number):
function Column_Nu_to_Letter(column_nu)
{
var temp, letter = '';
while (column_nu > 0)
{
temp = (column_nu - 1) % 26;
letter = String.fromCharCode(temp + 65) + letter;
column_nu = (column_nu - temp - 1) / 26;
}
return letter;
};
This is the code I came up for Dart, it works, but I am sure there is a more elegant or correct way to do it.
String colLetter = 'L'; //Column 'L' as example
int c = "A".codeUnitAt(0);
int end = "Z".codeUnitAt(0);
int counter = 1;
while (c <= end) {
//print(String.fromCharCode(c));
if(colLetter == String.fromCharCode(c)){
print('Conversion $colLetter = $counter');
}
counter++;
c++;
}
// this output L = 12
Do you have any suggestions on how to improve this code?
First we need to agree on the meaning of the letters.
I believe the traditional approach is "A" is 1, "Z" is 26, "AA" is 27, "AZ" is 52, "BA" is 53, etc.
Then I'd probably go with something like these functions for converting:
int lettersToIndex(String letters) {
var result = 0;
for (var i = 0; i < letters.length; i++) {
result = result * 26 + (letters.codeUnitAt(i) & 0x1f);
}
return result;
}
String indexToLetters(int index) {
if (index <= 0) throw RangeError.range(index, 1, null, "index");
const _letters = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
if (index < 27) return _letters[index - 1];
var letters = <String>[];
do {
index -= 1;
letters.add(_letters[index.remainder(26)]);
index ~/= 26;
} while (index > 0);
return letters.reversed.join("");
}
The former function doesn't validate that the input only contains letters, but it works correctly for strings containing only letters (and it ignores case as a bonus).
The latter does check that the index is greater than zero.
A simplified version base on Irn's answer
int lettersToIndex(String letters) =>
letters.codeUnits.fold(0, (v, e) => v * 26 + (e & 0x1f));
String indexToLetters(int index) {
var letters = '';
do {
final r = index % 26;
letters = '${String.fromCharCode(64 + r)}$letters';
index = (index - r) ~/ 26;
} while (index > 0);
return letters;
}
This is my String and i have problems when splitting into string array with comma seperated values for keys
{ Yr = 2019, Mth = DECEMBER , SeqN = 0, UComment = tet,tet1, OComment = test,test1, FWkMth = WK, FSafety = Y, FCustConsign = Y, FNCNRPull = 0, FNCNRPush = 0, CreatedTime = 2020-01-03 06:16:53 }
when i try to use string.Split(',') i get "Ucomment = tet","tet1" as seperate array.
But i need to have split string[] when seperated by comma
UComment = tet,tet1
OComment = test,test1
I have tried using the regex ,(?=([^\"]\"[^\"]\")[^\"]$)" but it didnot work.
You may try matching on the regex pattern \S+\s*=\s*.*?(?=\s*,\s*\S+\s*=|\s*\}$):
string input = "{ Yr = 2019, Mth = DECEMBER , SeqN = 0, UComment = tet,tet1, OComment = test,test1, FWkMth = WK, FSafety = Y, FCustConsign = Y, FNCNRPull = 0, FNCNRPush = 0, CreatedTime = 2020-01-03 06:16:53 }";
Regex regex = new Regex(#"\S+\s*=\s*.*?(?=\s*,\s*\S+\s*=|\s*\}$)");
var results = regex.Matches(input);
foreach (Match match in results)
{
Console.WriteLine(match.Groups[0].Value);
}
This prints:
Yr = 2019
Mth = DECEMBER
SeqN = 0
UComment = tet,tet1
OComment = test,test1
FWkMth = WK
FSafety = Y
FCustConsign = Y
FNCNRPull = 0
FNCNRPush = 0
CreatedTime = 2020-01-03 06:16:53
Here is an explanation of the regex pattern used:
\S+ match a key
\s* followed by optional whitespace and
= literal '='
\s* more optional whitespace
.*? match anything until seeing
(?=\s*,\s*\S+\s*=|\s*\}$) that what follows is either the start of the next key/value OR
is the end of the input
I'm working on a problem where I want to do calculations on NSDates where a single NSDate gives different dd/mm/yyyy values in different time zones.
To do that I'm currently using New York City (EST) and Aukland, NZ, since they are frequently on different dates.
I'd like to be able to use the time zones on either side of the international date line, UTC+12, and UTC-12. There appears to be a standard abbreviation for UTC+12, ANAT, for Anadyr, Russia. However, the iOS implementation of TimeZone/NSTimeZone doesn't seem to recognize it. There also does not seem to be an abbreviation for UTC-12 (which would be in Alaska).
Does anybody know if there are such abbreviations for UTC+12 and UTC-12 that iOS (or Mac OS, for that matter) recognizes?
It looks like the answer is no.
I wrote some code to fetch all the system time zones, sort them by offset, and print them:
typealias timeZoneTuple = (abbreviation: String, name: String, offset: Int)
let timeZones = TimeZone.abbreviationDictionary
let mappedTimeZones: [timeZoneTuple] = timeZones
.map {key, value in
var offset = 0
if let timeZone = TimeZone(abbreviation: key) {
offset = timeZone.secondsFromGMT() / 3600
}
return (abbreviation: key, name: value, offset:offset)}
.sorted {$0.offset < $1.offset}
mappedTimeZones.forEach {
let abbreviation = $0.abbreviation.padding(toLength: 4, withPad: " ", startingAt: 0)
let name = $0.name.padding(toLength: 20, withPad: " ", startingAt: 0)
print("abbreviation = \(abbreviation), offset = \(name), val = \($0.offset)")}
The output of the above code is:
abbreviation = HST , offset = Pacific/Honolulu , val = -10
abbreviation = AKDT, offset = America/Juneau , val = -9
abbreviation = AKST, offset = America/Juneau , val = -9
abbreviation = PST , offset = America/Los_Angeles , val = -8
abbreviation = PDT , offset = America/Los_Angeles , val = -8
abbreviation = MDT , offset = America/Denver , val = -7
abbreviation = MST , offset = America/Denver , val = -7
abbreviation = CDT , offset = America/Chicago , val = -6
abbreviation = CST , offset = America/Chicago , val = -6
abbreviation = EDT , offset = America/New_York , val = -5
abbreviation = PET , offset = America/Lima , val = -5
abbreviation = EST , offset = America/New_York , val = -5
abbreviation = COT , offset = America/Bogota , val = -5
abbreviation = ADT , offset = America/Halifax , val = -4
abbreviation = AST , offset = America/Halifax , val = -4
abbreviation = CLT , offset = America/Santiago , val = -3
abbreviation = CLST, offset = America/Santiago , val = -3
abbreviation = ART , offset = America/Argentina/Bu, val = -3
abbreviation = BRST, offset = America/Sao_Paulo , val = -2
abbreviation = BRT , offset = America/Sao_Paulo , val = -2
abbreviation = GMT , offset = GMT , val = 0
abbreviation = WET , offset = Europe/Lisbon , val = 0
abbreviation = BST , offset = Europe/London , val = 0
abbreviation = WEST, offset = Europe/Lisbon , val = 0
abbreviation = UTC , offset = UTC , val = 0
abbreviation = CEST, offset = Europe/Paris , val = 1
abbreviation = WAT , offset = Africa/Lagos , val = 1
abbreviation = CET , offset = Europe/Paris , val = 1
abbreviation = CAT , offset = Africa/Harare , val = 2
abbreviation = MSD , offset = Europe/Moscow , val = 3
abbreviation = EAT , offset = Africa/Addis_Ababa , val = 3
abbreviation = IRST, offset = Asia/Tehran , val = 3
abbreviation = MSK , offset = Europe/Moscow , val = 3
abbreviation = EET , offset = Europe/Istanbul , val = 3
abbreviation = EEST, offset = Europe/Istanbul , val = 3
abbreviation = GST , offset = Asia/Dubai , val = 4
abbreviation = IST , offset = Asia/Calcutta , val = 5
abbreviation = PKT , offset = Asia/Karachi , val = 5
abbreviation = BDT , offset = Asia/Dhaka , val = 6
abbreviation = WIT , offset = Asia/Jakarta , val = 7
abbreviation = ICT , offset = Asia/Bangkok , val = 7
abbreviation = SGT , offset = Asia/Singapore , val = 8
abbreviation = HKT , offset = Asia/Hong_Kong , val = 8
abbreviation = PHT , offset = Asia/Manila , val = 8
abbreviation = KST , offset = Asia/Seoul , val = 9
abbreviation = JST , offset = Asia/Tokyo , val = 9
abbreviation = NZDT, offset = Pacific/Auckland , val = 13
abbreviation = NZST, offset = Pacific/Auckland , val = 13
So it looks like UTC-12, UTC-11, UTC-1, UTC+10, UTC+11, and UTC+12 are all missing from the "named" timezones that are available in Cocoa.
EDIT:
Based on a comment from #MattJohnson, it seems that the identifiers is a better way to get the list of available time zones. Modifying my code to use identifiers instead:
struct timeZoneStruct: CustomStringConvertible {
let identifier: String
var offset: Int
var description: String {
let displayOffset = String(format: "%3d", offset)
let displayIdentifier = (identifier + ",").padding(toLength: 30, withPad: " ", startingAt: 0)
return "identifier = \(displayIdentifier) offset = \(displayOffset)"
}
}
let timeZoneIDs = TimeZone.knownTimeZoneIdentifiers
let mappedTimeZones: [timeZoneStruct] = timeZoneIDs
.map {identifier in
var offset = 0
if let timeZone = TimeZone(identifier: identifier) {
offset = timeZone.secondsFromGMT() / 3600
}
return timeZoneStruct(identifier: identifier, offset: offset)}
.sorted {$0.offset < $1.offset}
mappedTimeZones.forEach {
print($0.description)
}
That yields a list of time zones ranging from UTC-11 (Pacific/Pago_pago) to UTC+14 (Pacific/Apia)
(There are quite a few duplicates for most time zones, so the list is too long to include here.)
So it seems there are defined time zones for offsets from UTC-11 to UTC+14. There is not a time zone for UTC-12 however, even though Baker Island, at Lat/Long: 0°12'N / 176°29'W, is in UTC-12. Curious.
This is the simplest way to get all timezones with their respective abbreviation.
P.S Not all timezones have their proper 3-Letter Abbreviations.
let timezoneList = NSTimeZone.knownTimeZoneNames
for i in 0...timezoneList.count - 1 {
let locale = NSTimeZone.init(name: timezoneList[i])
print("Region: \((locale?.name)!) Abbr: \((locale?.abbreviation)!)")
}
Also total 51, 3-lettered Abbreviations are present:
print(TimeZone.abbreviationDictionary.count)
You can also explore https://developer.apple.com/documentation/foundation/timezone for more.
Im trying to make a toString method that prints out a histogram that shows how often each character of the alphabet is used in a string. The most frequent character has to be 60 #s long, with the rest of the characters then scaled to match.
My issue is with making the equation that scales the rest of the letters to the correct length for the histogram. My current equation is (myArray[i]/max) * 60, but im getting really weird results.
If I put in "hello world" to be analyzed, L would be the most common occuring letter, seen 3 times. So L should have 60 #s for the histogram, h should have 20, o should have 40 etc. Instead im getting results like d : 10
e : 10
h : 10
l : 360
o : 20
r : 10
w : 10
Sorry for how sloppy this is right now, im just trying to figure out whats going on
public class LetterCounter
private static int[] alphabetArray;
private static String input;
/**
* Constructor for objects of class LetterCounter
*/
public LetterCounter()
{
alphabetArray = new int[26];
}
public void countLetters(String input) {
this.input = input;
this.input.toLowerCase();
//String s= input;
//s.toLowerCase();
for ( int i = 0; i < input.length(); i++ ) {
char ch= input.charAt(i);
if (ch >= 97 && ch <= 122){
alphabetArray[ch-'a']++;
}
}
}
public void getTotalCount() {
for (int i = 0; i < alphabetArray.length; i++) {
if(alphabetArray[i]>=0){
char ch = (char) (i+97);
System.out.println(ch +" : "+alphabetArray[i]);
}
}
}
public void reset() {
for (int i =0; i<alphabetArray.length; i++) {
if(alphabetArray[i]>=0){
alphabetArray[i]=0;
char ch = (char) (i+97);
System.out.println(ch +" : "+alphabetArray[i]);
}
}
}
public String toString() {
String s = "";
int max = alphabetArray[0];
int markCounter = 0;
for(int i =0; i<alphabetArray.length; i++) {
//finds the largest number of occurences for any letter in the string
if(alphabetArray[i] > max) {
max = alphabetArray[i];
}
}
for(int i =0; i<alphabetArray.length; i++) {
//trying to scale the rest of the characters down here
if(alphabetArray[i] > 0) {
markCounter = (alphabetArray[i] / max) * 60;
char ch = (char) (i+97);
System.out.println(ch +" : "+alphabetArray[i] + markCounter);
}
}
for (int i = 0; i < alphabetArray.length; i++) {
//prints the whole alphabet, total number of occurences for all chars
if(alphabetArray[i]>=0){
char ch = (char) (i+97);
System.out.println(ch +" : "+alphabetArray[i]);
}
}
return s;
}
}
There are many many problems with your code, but lets go one by one.
First of all, your print statement is simply misleading. Change it to
System.out.println(ch +" : "+alphabetArray[i] + " " + markCounter);
and you will see
d : 1 0
e : 1 0
h : 1 0
l : 3 60
o : 2 0
r : 1 0
w : 1 0
As you can see: the counters are correct (1,1,1,3,2,1,1). But the your scaling doesn't work:
1 / 3 --> 0 ... and 0 * 3 ... is still 0
3 / 3 --> 1 and 1 * 3 ... is 60
but of course, when you dont print a space between 1 and 0 and 3 and 60.
Thus to get correct scaling, just change to:
markCounter = alphabetArray[i] * 60 / max;
Other things worth mentioning:
You are overriding toString(). Then you should put #Override in fron t of that method
toLowerCase() returns a new string in lower case; just calling it without pushing the result back into your string ... just throws away the "lower casing".
toString() shouldnt print to the console. The whole idea is that you put all the information into the string that you return. In other words: in the end you do some System.out.println(someLetterCounter.toString()
Your code is extremely low-level. You don't iterate arrays using for (int), you can do (int letter : alphabetArray) instead
You might want to read about Map. You see, if you would be using a Map<Character, Integer> where the map key would represent the different characters, and the map value represents a counter for each character ... well, you could throw out most of your code; and come up with a solution that would require a few lines of code only!
( and seriously: because of all these issues, debugging your code was really much harder than it needed to be )
countLetters seems has some issues. You can not convert String to lowercase by just calling
this.input.toLowerCase();
Because String is immutable in java. You have to assign it like:
this.input = input.toLowerCase();
Another problem is you are using input variable from parameter instead of this.input which has lower case string. You can do this way to make work countLetters method:
public void countLetters(String input) {
this.input = input.toLowerCase();
for ( int i = 0; i < this.input.length(); i++ ) {
char ch= this.input.charAt(i);
if (ch >= 97 && ch <= 122) {
alphabetArray[ch-'a']++;
}
}
}
My string format is: M/d/yyyy h:m:s aa
Now, I want to change it in yyyy-MM-ddTHH:mm:ss format.
How can I change it in this format. Please tell me appropriate solution
The method getConvertedDate(String), will do a plain text parsing for conversion.
private String getConvertedDate(String inputDate) {
// extract and adjust Month
int index = inputDate.indexOf('/');
String month = inputDate.substring(0, index);
if (month.length() < 2) {
month = "0" + month;
}
// extract and adjust Day
inputDate = inputDate.substring(index + 1);
index = inputDate.indexOf('/');
String day = inputDate.substring(0, index);
if (day.length() < 2) {
day = "0" + day;
}
// extract Year
inputDate = inputDate.substring(index + 1);
index = inputDate.indexOf(' ');
String year = inputDate.substring(0, index);
// extract Hour
inputDate = inputDate.substring(index + 1);
index = inputDate.indexOf(':');
String hour = inputDate.substring(0, index);
// extract and adjust Minute
inputDate = inputDate.substring(index + 1);
index = inputDate.indexOf(':');
String minute = inputDate.substring(0, index);
if (minute.length() < 2) {
minute = "0" + minute;
}
// extract and adjust Second
inputDate = inputDate.substring(index + 1);
index = inputDate.indexOf(' ');
String second = inputDate.substring(0, index);
if (second.length() < 2) {
second = "0" + second;
}
// extract AM/PM marker
// adjust hour, +12 for PM
inputDate = inputDate.substring(index + 1);
String am_pm_marker = inputDate.substring(0);
if (am_pm_marker.equalsIgnoreCase("pm")) {
int hourValue = 0;
try {
hourValue = Integer.parseInt(hour);
} catch (Exception e) {
}
hourValue += 12;
hour = "" + hourValue;
if (hour.length() < 2) {
hour = "0" + hour;
}
} else {
if (hour.length() < 2) {
hour = "0" + hour;
}
}
String outputDate = year + "-" + month + "-" + day;
outputDate += "T" + hour + ":" + minute + ":" + second;
return outputDate;
}
Sample input and output:
String input = "04/01/2012 9:55:47 pm";
System.out.println("Output: " + getConvertedDate(input));
// Output: 2012-04-01T21:55:47
Date date = (Date)new SimpleDateFormat("M/d/yyyy h:m:s aa").parse(your_string_date);
String finalFormat = new SimpleDateFormat("yyyy-MM-ddTHH:mm:ss").format(date)
Basically the first SimpleDateFormat recognizes your original format and parses it into a Date. Then the second one formats the date object to what you need.
I don't have jdk around to test here, but it should work.
Check this links for format syntax in case something doesn't work:
http://docs.oracle.com/javase/1.4.2/docs/api/java/text/SimpleDateFormat.html